@@ -7,7 +7,7 @@ const Settings = { | |||
fixedHeader: false, | |||
fixSiderbar: true, | |||
colorWeak: false, | |||
title: '黑菠萝智慧后厨', | |||
title: '配料系统', | |||
pwa: false, | |||
logo: '/logo.svg', | |||
iconfontUrl: '', | |||
@@ -9,7 +9,7 @@ | |||
export default { | |||
dev: { | |||
'/saasbase/': { | |||
target: 'http://localhost:5006/', | |||
target: 'http://192.168.1.50:5006/', | |||
changeOrigin: true, | |||
secure: false, //关闭证书验证 | |||
pathRewrite: { | |||
@@ -17,7 +17,7 @@ | |||
}, | |||
}, | |||
'/kitchbase/': { | |||
target: 'http://localhost:5007/', | |||
target: 'http://192.168.1.50:5007/', | |||
changeOrigin: true, | |||
secure: false, //关闭证书验证 | |||
pathRewrite: { | |||
@@ -25,7 +25,7 @@ | |||
}, | |||
}, | |||
'/kitchorder/': { | |||
target: 'http://localhost:5005/', | |||
target: 'http://192.168.1.50:5005/', | |||
changeOrigin: true, | |||
secure: false, //关闭证书验证 | |||
pathRewrite: { | |||
@@ -44,7 +44,7 @@ | |||
}, | |||
test: { | |||
'/api/': { | |||
target: 'http://localhost:5006', | |||
target: 'http://192.168.1.50:5006', | |||
changeOrigin: true, | |||
secure: false, | |||
pathRewrite: { | |||
@@ -54,7 +54,7 @@ | |||
}, | |||
pre: { | |||
'/api/': { | |||
target: 'http://localhost:5006', | |||
target: 'http://192.168.1.50:5006', | |||
changeOrigin: true, | |||
secure: false, | |||
pathRewrite: { | |||
@@ -40,13 +40,13 @@ export default [ | |||
// component: './sys/dictionary/dictdata', | |||
// access: 'k6', | |||
// }, | |||
{ | |||
name: '字典类型', | |||
icon: 'smile', | |||
path: '/sys/dictionary/dicttype', | |||
component: './sys/dictionary/dicttype', | |||
access: 'k6', | |||
}, | |||
// { | |||
// name: '字典类型', | |||
// icon: 'smile', | |||
// path: '/sys/dictionary/dicttype', | |||
// component: './sys/dictionary/dicttype', | |||
// access: 'k6', | |||
// }, | |||
// { | |||
// name: '操作日志', | |||
// icon: 'smile', | |||
@@ -61,7 +61,13 @@ export default [ | |||
// component: './sys/log', | |||
// access: 'k3', | |||
// }, | |||
{ | |||
name: '设备日志', | |||
icon: 'smile', | |||
path: '/sys/devicelog', | |||
component: './sys/devicelog', | |||
access: 'k3', | |||
}, | |||
], | |||
}, | |||
{ | |||
@@ -360,6 +366,76 @@ export default [ | |||
} | |||
], | |||
}, | |||
{ | |||
name: '接口文档', | |||
icon: 'smile', | |||
path: '/interfacedoc/index', | |||
component: './interfacedoc/index', | |||
access: 'k12' | |||
}, | |||
{ | |||
name: '物料管理', | |||
icon: 'BankFilled', | |||
path: '/batching', | |||
routes: [ | |||
{ | |||
name: '物料信息', | |||
icon: 'smile', | |||
path: '/batching/batchinginfo', | |||
component: './batching/batchinginfo', | |||
access: 'k12', | |||
} | |||
] | |||
}, | |||
{ | |||
name: '配方管理', | |||
icon: 'BankFilled', | |||
path: '/recipe', | |||
routes: [ | |||
{ | |||
name: '配方信息', | |||
icon: 'smile', | |||
path: '/recipe/recipeinfo', | |||
component: './recipe/recipeinfo', | |||
access: 'k12', | |||
} | |||
] | |||
}, | |||
{ | |||
name: '门店管理', | |||
icon: 'BankFilled', | |||
path: '/store', | |||
routes: [ | |||
{ | |||
name: '门店基础信息', | |||
icon: 'smile', | |||
path: '/store/storeinfo', | |||
component: './store/storeinfo', | |||
access: 'k12', | |||
} | |||
] | |||
}, | |||
{ | |||
name: '报表管理', | |||
icon: 'BankFilled', | |||
path: '/report', | |||
routes: [ | |||
{ | |||
name: '配方明细', | |||
icon: 'smile', | |||
path: '/report/recipereport', | |||
component: './report/recipereport', | |||
access: 'k12', | |||
}, | |||
{ | |||
name: '物料明细', | |||
icon: 'smile', | |||
path: '/report/batchingreport', | |||
component: './report/batchingreport', | |||
access: 'k12', | |||
} | |||
] | |||
}, | |||
{ | |||
path: '/', | |||
redirect: '/welcome', | |||
@@ -0,0 +1,67 @@ | |||
import { Modal, Form, TreeSelect, Button, Input } from 'antd'; | |||
const CreateForm = (props) => { | |||
return ( | |||
<Modal | |||
title={props.values.id ? '编辑物料' : '新建物料'} | |||
width={640} | |||
bodyStyle={{ padding: '32px 40px 1px 48px' }} | |||
visible={props.modalVisible} | |||
onCancel={props.onCancel} | |||
footer={null} | |||
maskClosable={false} | |||
destroyOnClose | |||
> | |||
<Form | |||
layout="horizontal" | |||
preserve={false} | |||
labelCol={{ | |||
span: 4, | |||
}} | |||
initialValues={props.values} | |||
onFinish={props.onFinish} | |||
> | |||
<Form.Item name="id" hidden={true}> | |||
<Input /> | |||
</Form.Item> | |||
<Form.Item name="name" label="物料名称" rules={[{ required: true }]}> | |||
<Input placeholder='请输入物料名称'/> | |||
</Form.Item> | |||
<Form.Item name="code" label="物料编码"> | |||
<Input disabled={true} /> | |||
</Form.Item> | |||
<Form.Item name="type" label="物料类型"> | |||
<TreeSelect | |||
style={{ width: '100%' }} | |||
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }} | |||
treeData={props.typeList} | |||
placeholder="请选择物料类型" | |||
treeDefaultExpandAll | |||
allowClear | |||
/> | |||
</Form.Item> | |||
<Form.Item name="stockUint" label="物料单位"> | |||
<TreeSelect | |||
style={{ width: '100%' }} | |||
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }} | |||
treeData={props.uintList} | |||
placeholder="请选择物料单位" | |||
treeDefaultExpandAll | |||
allowClear | |||
/> | |||
</Form.Item> | |||
<Form.Item> | |||
<Button htmlType="button" style={{ float: 'right', left: 10 }} onClick={props.onCancel}> | |||
取消 | |||
</Button> | |||
<Button type="primary" htmlType="submit" style={{ float: 'right' }}> | |||
保存 | |||
</Button> | |||
</Form.Item> | |||
</Form> | |||
</Modal> | |||
) | |||
} | |||
export default CreateForm; |
@@ -0,0 +1,224 @@ | |||
import { PlusOutlined } from '@ant-design/icons'; | |||
import { Button, message, Popconfirm } from 'antd'; | |||
import React, { useState, useRef } from 'react'; | |||
import { PageContainer } from '@ant-design/pro-layout'; | |||
import ProTable from '@ant-design/pro-table'; | |||
import CreateForm from './components/CreateForm'; | |||
import api from './service'; | |||
import { randomString } from '../../comm'; | |||
const batchinginfo = () => { | |||
const actionRef = useRef(); | |||
const [createModalVisible, handleModalVisible] = useState(); | |||
const [stepFormValues, setStepFormValues] = useState({}); | |||
const [selectedRowsState, setSelectedRows] = useState(); | |||
const uintList = [ | |||
{ value: '1', label: 'g' }, | |||
{ value: '2', label: 'kg' }, | |||
]; | |||
const typeList = [ | |||
{ value: '1', label: '液体料' }, | |||
{ value: '2', label: '主料' }, | |||
]; | |||
const handleAdd = async (fields) => { | |||
await api.add(fields).then((r) => { | |||
if (r.data) { | |||
message.success('添加成功'); | |||
} else { | |||
message.error(r.errors); | |||
} | |||
}); | |||
}; | |||
const handleUpdate = async (fields) => { | |||
await api.update(fields).then((r) => { | |||
if (r.data) { | |||
message.success('修改成功'); | |||
} else { | |||
message.error(r.errors); | |||
} | |||
}); | |||
}; | |||
const BatchDeletion = () => { | |||
return ( | |||
selectedRowsState?.length > 0 && | |||
( | |||
<Popconfirm | |||
title="确认删除吗?" | |||
onConfirm={onClickdele} | |||
okText="确定" | |||
cancelText="取消" | |||
> | |||
<Button type="primary">批量删除</Button> | |||
</Popconfirm> | |||
)) | |||
} | |||
const onClickdele = () => { | |||
handleRemove(selectedRowsState); | |||
setSelectedRows([]); | |||
actionRef.current?.reloadAndRest?.(); | |||
} | |||
const handleRemove = async (selectedRows) => { | |||
if (!selectedRows) return true; | |||
await api.delete(selectedRows.map((row) => row.id)).then((r) => { | |||
if (r.data) { | |||
message.success('删除成功'); | |||
actionRef.current.reload(); | |||
} else { | |||
message.error(r.errors); | |||
} | |||
}); | |||
return true; | |||
}; | |||
const columns = [ | |||
{ | |||
title: '主键', | |||
dataIndex: 'id', | |||
tip: 'key', | |||
hideInSearch: true, | |||
hideInTable: true | |||
}, | |||
{ | |||
title: '物料名称', | |||
dataIndex: 'name', | |||
ellipsis: true, | |||
}, | |||
{ | |||
title: '物料编码', | |||
dataIndex: 'code', | |||
ellipsis: true, | |||
hideInSearch: true, | |||
}, | |||
{ | |||
title: '物料类别', | |||
dataIndex: 'type', | |||
valueType: 'select', | |||
fieldProps: { | |||
options: typeList, | |||
}, | |||
}, | |||
{ | |||
title: '物料单位', | |||
dataIndex: 'stockUint', | |||
valueType: 'select', | |||
fieldProps: { | |||
options: uintList, | |||
}, | |||
}, | |||
{ | |||
title: '创建时间', | |||
dataIndex: 'createAt', | |||
valueType: 'date', | |||
hideInForm: true, | |||
hideInSearch: true, | |||
}, | |||
{ | |||
title: '操作', | |||
dataIndex: 'option', | |||
valueType: 'option', | |||
fixed: 'right', | |||
width: 350, | |||
render: (_, record) => [ | |||
<a | |||
onClick={() => { | |||
handleModalVisible(true); | |||
setStepFormValues(record); | |||
}} | |||
> | |||
更新 | |||
</a>, | |||
<Popconfirm | |||
type="primary" | |||
key="primary" | |||
title="确认删除吗?" | |||
okText="是" | |||
cancelText="否" | |||
onConfirm={() => { | |||
api.deleteBatching([record.id]).then((r) => { | |||
if (r.succeeded) { | |||
message.success('删除成功'); | |||
actionRef.current.reload(); | |||
} else { | |||
message.error(r.errors); | |||
} | |||
}); | |||
}} | |||
> | |||
<a href="#">删除</a> | |||
</Popconfirm>, | |||
], | |||
} | |||
] | |||
return ( | |||
<PageContainer | |||
header={{ | |||
title: '', | |||
breadcrumb: {}, | |||
}} | |||
> | |||
<ProTable | |||
headerTitle="物料列表" | |||
actionRef={actionRef} | |||
rowKey="id" | |||
pagination={{ defaultPageSize: 10 }} | |||
search={{ | |||
labelWidth: 120, | |||
}} | |||
toolBarRender={() => [ | |||
<Button | |||
type="primary" | |||
key="primary" | |||
onClick={() => { | |||
var values = { code: randomString(4) } | |||
setStepFormValues(values); | |||
handleModalVisible(true); | |||
}} | |||
> | |||
<PlusOutlined /> 新建 | |||
</Button>, | |||
<BatchDeletion /> | |||
]} | |||
request={async (params) => { | |||
let batchingData = []; | |||
var total = 0; | |||
await api.getBatchingPage(params).then((r) => { | |||
batchingData = r.data.data; | |||
total = r.data.total; | |||
}); | |||
return { | |||
data: batchingData, | |||
total: total, | |||
}; | |||
}} | |||
columns={columns} | |||
rowSelection={{ | |||
onChange: (_, selectedRows) => { | |||
setSelectedRows(selectedRows); | |||
}, | |||
}} | |||
/> | |||
<CreateForm | |||
uintList={uintList} | |||
typeList={typeList} | |||
onFinish={async (value) => { | |||
setStepFormValues({}); | |||
if (value.id) { | |||
await handleUpdate(value); | |||
} else { | |||
await handleAdd(value); | |||
} | |||
handleModalVisible(false); | |||
actionRef.current.reload(); | |||
}} | |||
onCancel={() => { | |||
handleModalVisible(false); | |||
setStepFormValues({}); | |||
}} | |||
modalVisible={createModalVisible} | |||
values={stepFormValues || {}} | |||
/> | |||
</PageContainer> | |||
) | |||
} | |||
export default batchinginfo; |
@@ -0,0 +1,34 @@ | |||
import { request } from 'umi'; | |||
import { getDataBaseUrl } from '@/global_data'; | |||
export default { | |||
getBatchingPage(params) { | |||
return request(getDataBaseUrl() + '/api/batching/getBatchingPage', { | |||
method: 'Post', | |||
data: params, | |||
}); | |||
}, | |||
deleteBatching(data) { | |||
return request(getDataBaseUrl() + `/api/batching/delete`, { | |||
method: 'Post', | |||
data: data, | |||
}); | |||
}, | |||
add(params) { | |||
return request(getDataBaseUrl() + '/api/batching/add', { | |||
method: 'Post', | |||
data: params, | |||
}); | |||
}, | |||
update(params) { | |||
return request(getDataBaseUrl() + '/api/batching/update', { | |||
method: 'Post', | |||
data: params, | |||
}); | |||
}, | |||
delete(data) { | |||
return request(getDataBaseUrl()+`/api/batching/delete`, { | |||
method: 'Post', | |||
data: data, | |||
}); | |||
}, | |||
} |
@@ -33,7 +33,7 @@ const CreateForm = (props) => { | |||
<Input placeholder="请输入管理员姓名" /> | |||
</Form.Item> | |||
<Form.Item name="email" label="登陆账号(手机号)" | |||
<Form.Item name="phone" label="登陆账号(手机号)" | |||
tooltip="初始密码为:123456" | |||
rules={[{ required: true, max: 50,message:"请输入手机号"},{pattern: /^1[3-9][0-9]{9}$/, | |||
message: '手机号格式不正确', }]}> | |||
@@ -160,11 +160,6 @@ const companyManage = () => { | |||
dataIndex: 'adminName', | |||
ellipsis: true, | |||
}, | |||
{ | |||
title: '邮箱账号', | |||
dataIndex: 'email', | |||
ellipsis: true, | |||
}, | |||
{ | |||
title: '电话', | |||
dataIndex: 'phone', | |||
@@ -338,7 +333,6 @@ const companyManage = () => { | |||
if (value.id) { | |||
success = await handleUpdate(value); | |||
} else { | |||
value.phone=value.email; | |||
success = await handleAdd(value); | |||
} | |||
if (success) { | |||
@@ -57,7 +57,7 @@ export default { | |||
}, | |||
/** 获取角色菜单*/ | |||
GetRoleMenu(params) { | |||
return request(getDataBaseUrl()+`/api/roles/getmenurole/?RoleId=${params}`); | |||
return request(getDataBaseUrl()+`/api/roles/getmenurole?RoleId=${params}`); | |||
}, | |||
/** 授权菜单功能获取数据*/ | |||
menutreepage(params) { | |||
@@ -1,151 +1,67 @@ | |||
import React, { useState, useEffect,useRef } from 'react'; | |||
import { PlusOutlined } from '@ant-design/icons'; | |||
import { Modal, Form, Input, Button, Select,Radio,Divider,Space,message } from 'antd'; | |||
import { | |||
GetDeviceVesion, | |||
AddDeviceType | |||
} from '../services'; | |||
import { Modal, Form, TreeSelect, Button, Input } from 'antd'; | |||
const CreateForm = (props) => { | |||
const [deviceTypename,setdeviceTypename]=useState(""); | |||
const [options,setoptions]=useState([]); | |||
const [stopoptions,setstopoptions]=useState([]); | |||
const [vesionoptions,setvesionoptions]=useState([]); | |||
const inputRef = useRef(null); | |||
useEffect(() => { | |||
if (Object.keys(props.values).length > 0) { | |||
var vesiondata = props.deviceVersions.map((item) => { | |||
return { value: item.id, label: item.vesion } | |||
}) | |||
} | |||
setvesionoptions(vesiondata); | |||
var optdata = props.dicData.map((item) => { | |||
return { value: item.id, label: item.label } | |||
}) | |||
setoptions(optdata); | |||
var stopData = props.StopData?.map((item) => { | |||
return { value: item.id, label: item.name } | |||
}) | |||
setstopoptions(stopData) | |||
}, [props]) | |||
const handleChange=(value)=>{ | |||
GetDeviceVesion(value).then((res)=>{ | |||
var vesiondata = res.data.map((item) => ({ | |||
value: item.id, label: item.vesion | |||
})) | |||
setvesionoptions(vesiondata); | |||
}) | |||
} | |||
const onNameChange=(event)=>{ | |||
setdeviceTypename(event.target.value); | |||
} | |||
const addItem=(e)=>{ | |||
e.preventDefault(); | |||
if(deviceTypename.length==0){ | |||
message.error("请输入名称"); | |||
}else{ | |||
var parm={name:deviceTypename} | |||
AddDeviceType(parm).then((r)=>{ | |||
if(r.succeeded){ | |||
message.success('添加成功'); | |||
props.initDeviceType() | |||
setdeviceTypename(''); | |||
}else{ | |||
message.error(r.errors); | |||
} | |||
}) | |||
} | |||
} | |||
const { TextArea } = Input; | |||
return ( | |||
<Modal | |||
title={props.values.id ? '编辑' : '新建'} | |||
title={props.values.id ? '编辑设备' : '新建设备'} | |||
width={640} | |||
visible={props.createModalVisible} | |||
maskClosable={false} | |||
bodyStyle={{ padding: '32px 40px 48px' }} | |||
bodyStyle={{ padding: '32px 40px 1px 48px' }} | |||
open={props.modalOpen} | |||
onCancel={props.onCancel} | |||
footer={null} | |||
onCancel={() => { | |||
props.onCancel(); | |||
}} | |||
destroyOnClose={true} | |||
maskClosable={false} | |||
destroyOnClose | |||
> | |||
<Form | |||
layout="Horizontal" | |||
labelCol={{ span: 4 }} | |||
layout="horizontal" | |||
preserve={false} | |||
labelCol={{ | |||
span: 4, | |||
}} | |||
initialValues={props.values} | |||
onFinish={props.onFinish} | |||
> | |||
<Form.Item name="id" hidden={true}> | |||
<Input /> | |||
</Form.Item> | |||
<Form.Item label={'选择场景'} name="stopId" rules={[{ required: true }]}> | |||
<Select allowClear showSearch optionFilterProp="children" filterOption={(input, option) => (option?.label ?? '').includes(input)} | |||
filterSort={(optionA, optionB) => | |||
(optionA?.label ?? '').toLowerCase().localeCompare((optionB?.label ?? '').toLowerCase()) } options={stopoptions}/> | |||
</Form.Item> | |||
<Form.Item label={'产品'} name="productId" rules={[{ required: true }]}> | |||
<Select onChange={handleChange} allowClear showSearch optionFilterProp="children" filterOption={(input, option) => (option?.label ?? '').includes(input)} | |||
filterSort={(optionA, optionB) => | |||
(optionA?.label ?? '').toLowerCase().localeCompare((optionB?.label ?? '').toLowerCase()) | |||
} options={options}/> | |||
<Form.Item name="name" label="设备名称" rules={[{ required: true }]}> | |||
<Input placeholder='请输入设备名称' /> | |||
</Form.Item> | |||
<Form.Item label={'产品版本'} name="productVersionId" rules={[{ required: true }]}> | |||
<Select allowClear showSearch optionFilterProp="children" filterOption={(input, option) => (option?.label ?? '').includes(input)} | |||
filterSort={(optionA, optionB) => (optionA?.label ?? '').toLowerCase().localeCompare((optionB?.label ?? '').toLowerCase())} options={vesionoptions}/> | |||
<Form.Item name="storeId" label="门店名称" rules={[{ required: true }]}> | |||
<TreeSelect | |||
style={{ width: '100%' }} | |||
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }} | |||
treeData={props.storeList} | |||
placeholder="请选择门店名称" | |||
treeDefaultExpandAll | |||
allowClear | |||
/> | |||
</Form.Item> | |||
<Form.Item label={'设备名称'} name="deviceName" rules={[{ required: true, max: 50 }]}> | |||
<Input /> | |||
</Form.Item> | |||
<Form.Item label={'设备标签'} name="deviceTypeId" rules={[{ required: false }]}> | |||
<Select | |||
style={{width: '100%'}} | |||
placeholder="请选设备标签" | |||
options={props.storeType} | |||
allowClear showSearch | |||
optionFilterProp="children" filterOption={(input, option) => (option?.label ?? '').includes(input)} | |||
filterSort={(optionA, optionB) => | |||
(optionA?.label ?? '').toLowerCase().localeCompare((optionB?.label ?? '').toLowerCase()) | |||
} | |||
dropdownRender={(menu) => ( | |||
<> | |||
{menu} | |||
<Divider style={{margin: '8px 0'}}/> | |||
<Space style={{padding: '0 8px 4px'}}> | |||
<Input | |||
placeholder="请输入设备标签" | |||
ref={inputRef} | |||
value={deviceTypename} | |||
onChange={onNameChange} | |||
onKeyDown={(e) => e.stopPropagation()} | |||
/> | |||
<Button type="text" icon={<PlusOutlined />} onClick={addItem}> | |||
新增 | |||
</Button> | |||
</Space> | |||
</> | |||
)} | |||
/> | |||
<Form.Item name="isEnable" label="使用情况" rules={[{ required: true }]}> | |||
<TreeSelect | |||
style={{ width: '100%' }} | |||
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }} | |||
treeData={props.enableList} | |||
placeholder="请选择使用情况" | |||
treeDefaultExpandAll | |||
allowClear | |||
/> | |||
</Form.Item> | |||
<Form.Item label={'地址'} name="address" rules={[{ max: 50 }]}> | |||
<Input /> | |||
<Form.Item name="remark" label="备注"> | |||
<TextArea rows={4} rules={[{ max: 500 }]} /> | |||
</Form.Item> | |||
{/* <Form.Item label={'支持功能'} name="technologyOrBom" rules={[{ required: true }]}> | |||
<Radio.Group onChange={onChange} value={value}> | |||
<Radio value={0}>工艺</Radio> | |||
<Radio value={1}>配方</Radio> | |||
</Radio.Group> | |||
</Form.Item> */} | |||
<Form.Item> | |||
<Button type="primary" htmlType="submit" style={{float:'right'}} > | |||
<Button htmlType="button" style={{ float: 'right', left: 10 }} onClick={props.onCancel}> | |||
取消 | |||
</Button> | |||
<Button type="primary" htmlType="submit" style={{ float: 'right' }}> | |||
保存 | |||
</Button> | |||
</Form.Item> | |||
</Form> | |||
</Modal> | |||
); | |||
}; | |||
) | |||
} | |||
export default CreateForm; | |||
export default CreateForm; |
@@ -1,164 +1,56 @@ | |||
import { PlusOutlined } from '@ant-design/icons'; | |||
import { Modal, Button, message, Popconfirm,Transfer } from 'antd'; | |||
import { Button, message, Popconfirm, Modal, Transfer, Select } from 'antd'; | |||
import React, { useState, useRef, useEffect } from 'react'; | |||
import { PageContainer } from '@ant-design/pro-layout'; | |||
import ProTable from '@ant-design/pro-table'; | |||
import CreateForm from './components/CreateForm'; | |||
import { | |||
GetDeviceInfoPage, | |||
GetProductList, | |||
AddDeviceInfo, | |||
UpdateDeviceInfo, | |||
DelDeviceInfo, | |||
GetDeviceType, | |||
GetDeviceVesion, | |||
GetStop, | |||
TechnologyTemplateExport, | |||
GoodsTemplateExport, | |||
Getgoodslist, | |||
getdevicegoods, | |||
editdevicegoodsapi, | |||
GetDeviceVersions | |||
} from './services'; | |||
import { gettree } from '../../org/orgamange/service'; | |||
import api from './service'; | |||
import './index.less'; | |||
import { forEach, values } from 'lodash'; | |||
const key = 'message'; | |||
const GoodsTypeManage = () => { | |||
const [storeType, setStoreType] = useState(); | |||
const [storeTypeArray, setStoreTypeArray] = useState([]); | |||
const [OrgList, setOrgList] = useState([]); | |||
const [OrgListArray, setOrgListArray] = useState([]); | |||
const [dicDataAny, setDicDataAny] = useState([]); | |||
const [dicData, setDicData] = useState([]); | |||
const [deviceVersion, setDeviceVersion] = useState([]); | |||
/** 新建/更新窗口的弹窗 */ | |||
const [createModalVisible, handleModalVisible] = useState(false); | |||
/** 分布更新窗口的弹窗 */ | |||
const deviceinfo = () => { | |||
const actionRef = useRef(); | |||
const [currentRow, setCurrentRow] = useState(); | |||
const [selectedRowsState, setSelectedRows] = useState([]); | |||
const [StopData, setStopData] = useState([]); | |||
const [selectedRowsState, setSelectedRows] = useState(); | |||
const [storeList, setStoreList] = useState([]); | |||
const [createModalOpen, handleModalOpen] = useState(); | |||
const [stepFormValues, setStepFormValues] = useState({}); | |||
const [isModalOpen, setIsModalOpen] = useState(false); | |||
const [mockData, setMockData] = useState([]); | |||
const [targetKeys, setTargetKeys] = useState([]); | |||
const [googsData,setGoogs]= useState([]); | |||
//初始化数据 | |||
const [deviceId, setDeviceId] = useState([]); | |||
const [storeId, setStoreId] = useState([]); | |||
const [isWeight, setIsWeight] = useState(''); | |||
const enableList = [ | |||
{ value: '1', label: '启用' }, | |||
{ value: '0', label: '停用' }, | |||
]; | |||
useEffect(() => { | |||
GetStop().then((t) => { | |||
setStopData(t.data) | |||
getAllStoreList() | |||
}, []); | |||
function getAllStoreList() { | |||
api.getAllStoreList().then((r) => { | |||
var data = r.data; | |||
const storeList = []; | |||
data.forEach((item) => { | |||
storeList.push({ | |||
value: item.id, | |||
label: item.name | |||
}) | |||
}) | |||
setStoreList(storeList); | |||
}); | |||
Getgoodslist().then((item) => { | |||
var data=item.data; | |||
} | |||
function getStoreRecipeList(id, isWeight) { | |||
api.getStoreRecipeList(id, isWeight).then((item) => { | |||
var data = item.data; | |||
const tempMockData = []; | |||
data.forEach((item)=>{ | |||
data.forEach((item) => { | |||
tempMockData.push({ | |||
key: item.id, | |||
title: item.name, | |||
description: item.name, | |||
}); | |||
}) | |||
setMockData(tempMockData); | |||
}); | |||
function initOrgList() { | |||
gettree().then((r) => { | |||
inittree(r.data); | |||
function inittree(datas) { | |||
for (var i in datas) { | |||
if (datas[i]['type'] == 2 || datas[i]['type'] == 3) { | |||
datas[i]['disabled'] = false; | |||
} else { | |||
datas[i]['disabled'] = true; | |||
} | |||
if (datas[i].children) { | |||
inittree(datas[i].children); | |||
} | |||
} | |||
} | |||
setOrgList(r.data); | |||
let list = {}; | |||
formateData(r.data); | |||
function formateData(datas) { | |||
for (var i in datas) { | |||
list[datas[i]['disabled']] = true; | |||
list[datas[i]['value']] = { text: datas[i]['title'] }; | |||
if (datas[i].children) { | |||
formateData(datas[i].children); | |||
} | |||
} | |||
} | |||
setOrgListArray(list); | |||
}); | |||
} | |||
initOrgList(); | |||
initDeviceType(); | |||
function intDicData() { | |||
GetProductList().then((r) => { | |||
var arr = r.data; | |||
let data = {}; | |||
if (r.succeeded) { | |||
var list = []; | |||
arr.forEach((item) => { | |||
data[item.name] = { text: item.name }; | |||
list.push({ | |||
id: item.id, | |||
label: item.name, | |||
text: item.name, | |||
}); | |||
}); | |||
setDicDataAny(data); | |||
setDicData(list); | |||
} | |||
}); | |||
} | |||
intDicData(); | |||
initDeviceVersionList(); | |||
}, []); | |||
const initDeviceType = () => { | |||
GetDeviceType().then((data) => { | |||
let list = {}; | |||
let list2 = []; | |||
data.data.forEach((item) => { | |||
list2.push({ | |||
label: item.name, | |||
text: item.name, | |||
value: item.id, | |||
}); | |||
list[item.id] = { text: item.name }; | |||
}); | |||
setStoreTypeArray(list2); | |||
setStoreType(list); | |||
}); | |||
}; | |||
const initDeviceVersionList = async()=>{ | |||
const response = await GetDeviceVersions(); | |||
if (response.statusCode == 200) { | |||
setDeviceVersion(response.data); | |||
} else { | |||
message.error('获取设备版本失败'); | |||
} | |||
} | |||
const initDeviceVersion = async (record) => { | |||
const response = await GetDeviceVesion(record?.productId); | |||
if (response.statusCode == 200) { | |||
setDeviceVersion(response.data); | |||
} else { | |||
message.error('获取设备版本失败'); | |||
} | |||
}; | |||
const BatchDeletion = () => { | |||
return ( | |||
selectedRowsState?.length > 0 && | |||
@@ -178,283 +70,168 @@ const GoodsTypeManage = () => { | |||
setSelectedRows([]); | |||
actionRef.current?.reloadAndRest?.(); | |||
} | |||
/** | |||
* 删除节点 | |||
* | |||
* @param selectedRows | |||
*/ | |||
const handleRemove = async (selectedRows) => { | |||
if (!selectedRows) return true; | |||
await DelDeviceInfo(selectedRows.map((row) => row.id)).then((r) => { | |||
await api.deleteDevice(selectedRows.map((row) => row.id)).then((r) => { | |||
if (r.data) { | |||
message.success('删除成功'); | |||
actionRef.current.reload(); | |||
} else { | |||
message.error('删除失败,请重试'); | |||
message.error(r.errors); | |||
} | |||
}); | |||
return true; | |||
}; | |||
/** 国际化配置 */ | |||
const editDeviceRecipe = async () => { | |||
const tempMockData = []; | |||
targetKeys.forEach(function (item, index, array) { | |||
tempMockData.push({ | |||
"recipeId": item | |||
}); | |||
}) | |||
var data = { | |||
"deviceId": deviceId, | |||
"recipeIdList": tempMockData | |||
} | |||
api.setDeviceRelation(data).then((r) => { | |||
if (r.succeeded) { | |||
message.success('编辑成功'); | |||
} else { | |||
message.error(r.errors) | |||
} | |||
}); | |||
setIsModalOpen(false); | |||
actionRef.current.reload(); | |||
}; | |||
const setrecipeList = async (id) => { | |||
var list = []; | |||
api.getDeviceRelation(id).then((item) => { | |||
item.data.forEach(function (item) { | |||
list.push(item.recipeId); | |||
}) | |||
setTargetKeys(list); | |||
}); | |||
}; | |||
const handleChange = (newTargetKeys) => { | |||
setTargetKeys(newTargetKeys); | |||
}; | |||
const handleModeChange = (value) => { | |||
setIsWeight(value); | |||
getStoreRecipeList(storeId, value); | |||
}; | |||
const columns = [ | |||
{ | |||
title: '主键', | |||
dataIndex: 'id', | |||
tip: 'key', | |||
hideInSearch: true, | |||
hideInTable: true, | |||
tip: '规则名称是唯一的 key', | |||
hideInTable: true | |||
}, | |||
{ | |||
title: '设备名称', | |||
dataIndex: 'deviceName', | |||
valueType: 'textarea', | |||
dataIndex: 'name', | |||
ellipsis: true, | |||
}, | |||
{ | |||
title: '产品', | |||
dataIndex: 'productName', | |||
valueEnum: dicDataAny, | |||
title: '门店名称', | |||
dataIndex: 'storeId', | |||
valueType: 'select', | |||
hideInSearch: true, | |||
fieldProps: { | |||
options: storeList, | |||
}, | |||
}, | |||
{ | |||
title: '产品版本', | |||
dataIndex: 'productVersionName', | |||
search: false, | |||
}, | |||
{ | |||
title: '所属场景', | |||
dataIndex: 'stopName', | |||
search: false, | |||
}, | |||
{ | |||
title: '地址', | |||
dataIndex: 'address', | |||
search: false, | |||
}, | |||
// { | |||
// title: '归属门店', | |||
// dataIndex: 'orgId', | |||
// search: false, | |||
// valueEnum: OrgListArray, | |||
// }, | |||
{ | |||
title: '设备标签', | |||
dataIndex: 'deviceTypeId', | |||
valueEnum: storeType, | |||
title: '使用情况', | |||
dataIndex: 'isEnable', | |||
valueType: 'select', | |||
hideInSearch: true, | |||
fieldProps: { | |||
options: enableList, | |||
}, | |||
}, | |||
{ | |||
title: '设备唯一key', | |||
dataIndex: 'autoKey', | |||
search: false, | |||
ellipsis: true, | |||
hideInSearch: true, | |||
}, | |||
{ | |||
title: '备注', | |||
dataIndex: 'remark', | |||
ellipsis: true, | |||
hideInSearch: true, | |||
}, | |||
// { | |||
// title: '归属门店唯一key', | |||
// dataIndex: 'orgKey', | |||
// search: false, | |||
// }, | |||
{ | |||
title: '操作', | |||
dataIndex: 'option', | |||
valueType: 'option', | |||
fixed: 'right', | |||
width: 300, | |||
width: 350, | |||
render: (_, record) => [ | |||
<a | |||
key="update" | |||
onClick={() => { | |||
initDeviceVersion(record); | |||
handleModalVisible(true); | |||
setCurrentRow(record); | |||
handleModalOpen(true); | |||
setStepFormValues(record); | |||
}} | |||
> | |||
更新 | |||
</a>, | |||
<a | |||
key="edit" | |||
onClick={() => { | |||
getStoreRecipeList(record.storeId, isWeight); | |||
setStoreId(record.storeId); | |||
setrecipeList(record.id); | |||
setDeviceId(record.id); | |||
setIsModalOpen(true); | |||
}} | |||
> | |||
设置设备配方 | |||
</a>, | |||
<Popconfirm | |||
type="primary" | |||
key="primary" | |||
title="确认删除吗?" | |||
okText="是" | |||
cancelText="否" | |||
onConfirm={async () => { | |||
await DelDeviceInfo([record.id]).then((r) => { | |||
if (r.data) { | |||
onConfirm={() => { | |||
api.deleteDevice([record.id]).then((r) => { | |||
if (r.succeeded) { | |||
message.success('删除成功'); | |||
actionRef.current.reload(); | |||
} else { | |||
message.error(r.errors); | |||
} | |||
}); | |||
}} | |||
onCancel={() => { }} | |||
> | |||
<a href="#">删除</a> | |||
</Popconfirm>, | |||
// <a | |||
// key="copy" | |||
// onClick={() => { | |||
// CopyDevice({ id: record.id }).then((r) => { | |||
// if (r.data) { | |||
// actionRef.current.reload(); | |||
// } | |||
// }); | |||
// }} | |||
// > | |||
// 复制 | |||
// </a>, | |||
// <a | |||
// key="upload-goods" | |||
// onClick={() => { | |||
// setCurrentRow(record); | |||
// setDeviceFoodModal(true); | |||
// }} | |||
// > | |||
// 绑定商品 | |||
// </a>, | |||
// <a | |||
// key="add" | |||
// onClick={() => { | |||
// setCurrentRow(record); | |||
// setStockModal(true); | |||
// }} | |||
// > | |||
// 库存原料 | |||
// </a>, | |||
<a | |||
key="add" | |||
onClick={async () => { | |||
const response = await TechnologyTemplateExport(record.id); | |||
if (response == '') { | |||
message.error('当前模板不存在!'); | |||
return; | |||
} | |||
// const blob = new Blob([response]); | |||
// const url = URL.createObjectURL(blob); | |||
// console.log(blob, url); | |||
// const link = document.createElement('a'); | |||
// link.download = `工艺模板_${new Date(Date.now()).toLocaleString()}.xls`; | |||
// link.href = url; | |||
// link.click(); | |||
const link = document.createElement('a'); | |||
link.href = response; | |||
link.click(); | |||
}} | |||
> | |||
导出工艺模版 | |||
</a>, | |||
// <a | |||
// key="edit" | |||
// onClick={() => { | |||
// GetdevicegoodsList(record.id); | |||
// setCurrentRow(record); | |||
// setIsModalOpen(true); | |||
// }} | |||
// > | |||
// 设置设备商品 | |||
// </a>, | |||
], | |||
}, | |||
]; | |||
//添加 | |||
const handleAdd = async (fields) => { | |||
await AddDeviceInfo(JSON.stringify(fields)).then((r) => { | |||
if (r.succeeded) { | |||
message.success('添加成功'); | |||
handleModalVisible(false); | |||
actionRef.current.reload(); | |||
} else { | |||
message.error(r.errors) | |||
return false; | |||
} | |||
}); | |||
}; | |||
//修改 | |||
const handleUpdate = async (fields) => { | |||
await UpdateDeviceInfo(JSON.stringify(fields)).then((r) => { | |||
if (r.succeeded) { | |||
message.success('更新成功'); | |||
handleModalVisible(false); | |||
actionRef.current.reload(); | |||
} else { | |||
message.error(r.errors) | |||
return false; | |||
} | |||
}); | |||
}; | |||
//修改 | |||
const editdevicegoods = async () => { | |||
const tempMockData = []; | |||
targetKeys.forEach(function (item, index, array) { | |||
tempMockData.push({ | |||
"goodsId" : item, | |||
"goodsName":"" | |||
}); | |||
}) | |||
var data={ | |||
"deviceId": currentRow.id, | |||
"goodsList": tempMockData, | |||
"autoKey":currentRow.autoKey | |||
} | |||
editdevicegoodsapi(data).then((r) => { | |||
if (r.succeeded) { | |||
message.success('编辑成功'); | |||
handleModalVisible(false); | |||
actionRef.current.reload(); | |||
} else { | |||
message.error(r.errors) | |||
return false; | |||
} | |||
}); | |||
setIsModalOpen(false); | |||
}; | |||
//修改 | |||
const GetdevicegoodsList = async (deviceId ) => { | |||
var list=[]; | |||
getdevicegoods(deviceId).then((item) => { | |||
item.data.forEach(function (item, index, array) { | |||
list.push(item.goodsId); | |||
}) | |||
setTargetKeys(list); | |||
}); | |||
}; | |||
const handleChange = (newTargetKeys) => { | |||
setTargetKeys(newTargetKeys); | |||
}; | |||
] | |||
return ( | |||
<PageContainer host header={{ | |||
title: '', | |||
breadcrumb: {}, | |||
}}> | |||
<PageContainer | |||
header={{ | |||
title: '', | |||
breadcrumb: {}, | |||
}} | |||
> | |||
<ProTable | |||
headerTitle="设备信息" | |||
headerTitle="设备列表" | |||
actionRef={actionRef} | |||
rowKey="id" | |||
pagination={{ defaultPageSize: 10 }} | |||
search={{ | |||
labelWidth: 120, | |||
}} | |||
scroll={{ x: 2000 }} | |||
toolBarRender={() => [ | |||
<Button | |||
type="primary" | |||
key="primary" | |||
onClick={() => { | |||
handleModalVisible(true); | |||
handleModalOpen(true); | |||
}} | |||
> | |||
<PlusOutlined /> 新建 | |||
@@ -462,23 +239,14 @@ const GoodsTypeManage = () => { | |||
<BatchDeletion /> | |||
]} | |||
request={async (params) => { | |||
var data = []; | |||
let storeData = []; | |||
var total = 0; | |||
await GetDeviceInfoPage(params).then((r) => { | |||
// console.log("StopData", r) | |||
// r.data.data.forEach(x=>{ | |||
// var stop=StopData.find(f=>f.id==x.stopId); | |||
// if(stop){ | |||
// x.stopName=stop.name | |||
// } | |||
// }) | |||
data = r.data.data; | |||
await api.getDevicePage(params).then((r) => { | |||
storeData = r.data.data; | |||
total = r.data.total; | |||
}); | |||
return { | |||
data: data, | |||
success: true, | |||
data: storeData, | |||
total: total, | |||
}; | |||
}} | |||
@@ -489,45 +257,72 @@ const GoodsTypeManage = () => { | |||
}, | |||
}} | |||
/> | |||
<CreateForm | |||
storeType={storeTypeArray} | |||
OrgData={OrgList} | |||
dicData={dicData} | |||
initDeviceType={initDeviceType} | |||
storeList={storeList} | |||
enableList={enableList} | |||
onFinish={async (value) => { | |||
if (value.id) { | |||
handleUpdate(value); | |||
} else { | |||
handleAdd(value); | |||
} | |||
await api.updateDevice(value).then(r => { | |||
if (r.data) { | |||
if (value.id == undefined) { | |||
message.success("添加成功") | |||
} | |||
else { | |||
message.success("修改成功") | |||
} | |||
} | |||
else { | |||
message.error(r.errors) | |||
} | |||
}) | |||
handleModalOpen(false); | |||
setStepFormValues({}); | |||
actionRef.current.reload(); | |||
}} | |||
onCancel={() => { | |||
handleModalVisible(false); | |||
setCurrentRow(undefined); | |||
handleModalOpen(false); | |||
setStepFormValues({}); | |||
}} | |||
createModalVisible={createModalVisible} | |||
deviceVersions={deviceVersion} | |||
values={currentRow || {}} | |||
StopData={StopData} | |||
modalOpen={createModalOpen} | |||
values={stepFormValues || {}} | |||
/> | |||
<Modal width={600} title="编辑设备商品" open={isModalOpen} onOk={() => {editdevicegoods() }} onCancel={() => { setIsModalOpen(false); }}> | |||
<Modal | |||
width={800} | |||
title="设置门店配方" | |||
open={isModalOpen} | |||
destroyOnClose | |||
onOk={() => { editDeviceRecipe() }} | |||
onCancel={() => { | |||
setIsModalOpen(false) | |||
setIsWeight('') | |||
}} | |||
> | |||
<Select | |||
defaultValue="全部" | |||
style={{ width: 120, marginBottom: 10 }} | |||
onChange={handleModeChange} | |||
> | |||
<Option value="">全部</Option> | |||
<Option value={false}>标准模式</Option> | |||
<Option value={true}>称重模式</Option> | |||
</Select> | |||
<Transfer | |||
className="tree-transfer" | |||
className="tree-transfer" | |||
listStyle={{ | |||
width: 500, | |||
height: 500, | |||
}} | |||
dataSource={mockData} | |||
targetKeys={targetKeys} | |||
onChange={handleChange} | |||
onSearch={()=>{}} | |||
showSearch | |||
pagination | |||
render={(item) => item.title} | |||
/> | |||
</Modal> | |||
</PageContainer> | |||
); | |||
}; | |||
) | |||
} | |||
export default GoodsTypeManage; | |||
export default deviceinfo; |
@@ -1,4 +0,0 @@ | |||
.tree-transfer .ant-transfer-list:first-child { | |||
flex: none; | |||
width: 50%; | |||
} |
@@ -0,0 +1,43 @@ | |||
import { request } from 'umi'; | |||
import { getDataBaseUrl } from '@/global_data'; | |||
export default { | |||
getDevicePage(params) { | |||
return request(getDataBaseUrl() + '/api/store/getDevicePage', { | |||
method: 'Post', | |||
data: params, | |||
}); | |||
}, | |||
getAllStoreList() { | |||
return request(getDataBaseUrl() + `/api/store/getAllStoreList`, { | |||
method: 'Get', | |||
}); | |||
}, | |||
updateDevice(data) { | |||
return request(getDataBaseUrl() + '/api/store/updateDevice', { | |||
method: 'Post', | |||
data: data, | |||
}); | |||
}, | |||
deleteDevice(data) { | |||
return request(getDataBaseUrl() + '/api/store/deleteDevice', { | |||
method: 'Post', | |||
data: data, | |||
}); | |||
}, | |||
getStoreRecipeList(id, isWeight) { | |||
return request(getDataBaseUrl() + `/api/recipe/getStoreRecipeList?storeId=${id}&isWeight=${isWeight}`, { | |||
method: 'Get', | |||
}); | |||
}, | |||
getDeviceRelation(id) { | |||
return request(getDataBaseUrl() + `/api/store/getDeviceRelation?deviceId=${id}`, { | |||
method: 'Get', | |||
}); | |||
}, | |||
setDeviceRelation(data) { | |||
return request(getDataBaseUrl() + '/api/store/setDeviceRelation', { | |||
method: 'Post', | |||
data: data, | |||
}); | |||
}, | |||
} |
@@ -1,247 +0,0 @@ | |||
import { request } from 'umi'; | |||
import { getDataBaseUrl,GetkitchbaseUrl } from '@/global_data'; | |||
/** 获取设备列表 */ | |||
export async function GetDeviceInfoPage(data) { | |||
return request(getDataBaseUrl()+`/api/device/page`, { | |||
method: 'POST', | |||
data: data, | |||
}); | |||
} | |||
/**获取产品 */ | |||
export async function GetProductList() { | |||
return request(getDataBaseUrl()+`/api/product/list`, { | |||
method: 'Get', | |||
}); | |||
} | |||
/** 添加设备 */ | |||
export async function AddDeviceInfo(data) { | |||
return request(getDataBaseUrl()+`/api/device/add`, { | |||
method: 'POST', | |||
data: data, | |||
}); | |||
} | |||
export async function PushDeviceGoods(data) { | |||
return request(getDataBaseUrl()+`/api/device/PushDeviceGoods?DeviceId=`+data, { | |||
method: 'Get', | |||
}); | |||
} | |||
/** 修改 */ | |||
export async function UpdateDeviceInfo(data) { | |||
return request(getDataBaseUrl()+`/api/device/update`, { | |||
method: 'POST', | |||
data: data, | |||
}); | |||
} | |||
/** 修改 */ | |||
export async function CopyDevice(data) { | |||
return request(getDataBaseUrl()+`/api/device/CopyDevice`, { | |||
method: 'POST', | |||
data: data, | |||
}); | |||
} | |||
/** 删除 */ | |||
export async function DelDeviceInfo(data) { | |||
return request(getDataBaseUrl()+`/api/device/delete`, { | |||
method: 'POST', | |||
data: data, | |||
}); | |||
} | |||
/** 获取所有设备标签 */ | |||
export async function GetDeviceType() { | |||
return request(getDataBaseUrl()+`/api/device/getdevicetypelist`, { | |||
method: 'GET', | |||
}); | |||
} | |||
/** 添加设备标签 */ | |||
export async function AddDeviceType(data) { | |||
return request(getDataBaseUrl()+`/api/device/adddevicetype`, { | |||
method: 'POST', | |||
data: data, | |||
}); | |||
} | |||
/** 获取所有设备版本 */ | |||
export async function GetDeviceVersions() { | |||
return request(getDataBaseUrl()+`/api/devicevesion/getdevicevesionlist`, { | |||
method: 'GET', | |||
}); | |||
} | |||
/** | |||
* 获取当前设备绑定的商品 | |||
* @param {*} params | |||
* @param {*} options | |||
* @returns | |||
*/ | |||
export async function GetDeviceGoods(params, options) { | |||
return request(getDataBaseUrl()+'/api/device/GetDeviceGoods', { | |||
method: 'POST', | |||
data: { | |||
...params, | |||
}, | |||
}); | |||
} | |||
/** | |||
* 为设备添加商品 | |||
* @param {*} params | |||
* @returns | |||
*/ | |||
export async function AddDeviceGood(params) { | |||
return request(getDataBaseUrl()+'/api/device/AddDeviceGood', { | |||
method: 'POST', | |||
data: { | |||
...params, | |||
}, | |||
}); | |||
} | |||
/** | |||
* 获取所有商品 | |||
* @param {*} params | |||
* @returns | |||
*/ | |||
export async function GetGoods(params) { | |||
return request(getDataBaseUrl()+'/api/device/GetGoods', { | |||
method: 'POST', | |||
data: { | |||
...params, | |||
}, | |||
}); | |||
} | |||
/** | |||
* 获取所有商品 | |||
* @param {*} params | |||
* @returns | |||
*/ | |||
export async function GetByDeviceGoods(params) { | |||
return request(getDataBaseUrl()+'/api/device/GetByDeviceGoods', { | |||
method: 'POST', | |||
data: { | |||
...params, | |||
}, | |||
}); | |||
} | |||
/** 获取商品物料库存 */ | |||
export async function GetDeviceStorePage(data) { | |||
return request(getDataBaseUrl()+`/api/device/GetDeviceStorePage`, { | |||
method: 'POST', | |||
data: data, | |||
}); | |||
} | |||
/** | |||
* 删除库存原料 | |||
* @param {*} data | |||
* @returns | |||
*/ | |||
export async function removeSingleStockAdjust(data) { | |||
return request(getDataBaseUrl()+`/api/device/DelStockAdjust?Id=${data}`, { | |||
method: 'DELETE', | |||
// data: data, | |||
// ...(options || {}), | |||
}); | |||
} | |||
/** 添加商品物料库存 */ | |||
export async function AddStoreBatchingStocAsync(data) { | |||
return request(getDataBaseUrl()+`/api/device/AddUpdateDeviceStocAsync`, { | |||
method: 'POST', | |||
data: data, | |||
}); | |||
} | |||
/** 修改商品物料库存 */ | |||
export async function UpdateStoreBatchingStocAsync(data) { | |||
return request(getDataBaseUrl()+`/api/device/AddUpdateDeviceStocAsync`, { | |||
method: 'put', | |||
data: data, | |||
}); | |||
} | |||
/**获取位置配置 */ | |||
export async function getloc(data) { | |||
return request(getDataBaseUrl()+`/api/deviceconfig/getlocs?Code=${data}`, { | |||
method: 'GET', | |||
}); | |||
} | |||
/** 获取原料 */ | |||
export async function GetBatchingAsync(data) { | |||
return request(getDataBaseUrl()+`/api/device/GetProductList`, { | |||
method: 'post', | |||
data: data, | |||
}); | |||
} | |||
/** | |||
* 获取菜谱列表 | |||
* @param {*} params | |||
* @returns | |||
*/ | |||
export async function getFoodMenuList(params) { | |||
return request(getDataBaseUrl()+'/api/FoodMenu/tree', { | |||
data: { | |||
...params, | |||
}, | |||
}); | |||
} | |||
/** 同步库存 */ | |||
export async function PushStockAsync(data) { | |||
return request(getDataBaseUrl()+`/api/device/PushDevice?DeviceId=${data}`, { | |||
method: 'post', | |||
}); | |||
} | |||
/** 获取实时库存 */ | |||
export async function CheckStockAdjust(data) { | |||
return request(getDataBaseUrl()+`/api/device/CheckStockAdjust?DeviceId=${data}`, { | |||
method: 'POST', | |||
}); | |||
} | |||
export async function GetDeviceVesion(TypeCode) { | |||
return request(getDataBaseUrl()+`/api/DeviceVesion/GetDeviceVesion?productId=${TypeCode}`, { | |||
method: 'Get', | |||
}); | |||
} | |||
export async function TechnologyTemplateExport(data) { | |||
return request(getDataBaseUrl()+`/api/goods/TechnologyTemplateExport?deviceId=${data}`, { | |||
method: 'post', | |||
// responseType: 'blob' | |||
}); | |||
} | |||
export async function GetStop() { | |||
return request(GetkitchbaseUrl()+`/api/store/getstorelist`, { | |||
method: 'Get', | |||
}); | |||
} | |||
//获取全部商品信息 | |||
export async function Getgoodslist() { | |||
return request(getDataBaseUrl()+`/api/goods/getgoodslist`, { | |||
method: 'Get', | |||
}); | |||
} | |||
//获取设备商品信息 | |||
export async function getdevicegoods(deviceId) { | |||
return request(GetkitchbaseUrl()+`/api/devicepushrecode/getdevicegoods?deviceId=`+deviceId, { | |||
method: 'post', | |||
}); | |||
} | |||
export async function editdevicegoodsapi(data) { | |||
return request(GetkitchbaseUrl()+`/api/devicepushrecode/editdevicegoods`, { | |||
method: 'post', | |||
data: data, | |||
}); | |||
} | |||
@@ -0,0 +1,18 @@ | |||
const interfacedoc = () => { | |||
return ( | |||
<div style={{ width: '100%', height: '107%', overflow: 'hidden' ,background: '#ffffff' }}> | |||
<iframe | |||
src="http://localhost:8001/" | |||
title="接口文档" | |||
style={{ | |||
width: '100%', | |||
height: '100%', | |||
border: 'none', | |||
}} | |||
/> | |||
</div> | |||
) | |||
}; | |||
export default interfacedoc; |
@@ -54,7 +54,7 @@ export async function setMenu(params) { | |||
//获取角色菜单 | |||
export async function GetRoleMenu(params) { | |||
return request(getDataBaseUrl()+`/api/roles/getmenurole/?RoleId=${params}`); | |||
return request(getDataBaseUrl()+`/api/roles/getmenurole?RoleId=${params}`); | |||
} | |||
//数据授权 | |||
@@ -0,0 +1,203 @@ | |||
import React, { useState, useRef, useEffect } from 'react'; | |||
import { CloseOutlined } from '@ant-design/icons'; | |||
import { Modal, Form, Input, Button, InputNumber, TreeSelect, Card, Space, message } from 'antd'; | |||
import { ProCard } from '@ant-design/pro-Card'; | |||
import api from '../service'; | |||
const CreateAttrForm = (props) => { | |||
const [form] = Form.useForm(); | |||
const [expandedCardKeys, setExpandedCardKeys] = useState([]); | |||
const [inputValues, setInputValues] = useState([]); | |||
useEffect(() => { | |||
if (props.values != undefined) { | |||
if (Object.keys(props.values).length > 0) { | |||
var inputs = props.values.map((item, index) => { | |||
return { index: index, value: item.name } | |||
}) | |||
setInputValues(inputs) | |||
} | |||
} | |||
else { | |||
setInputValues({ index: 0, value: '' }) | |||
} | |||
if (props.modalVisible) { | |||
form.resetFields(); | |||
if (props.values) { | |||
form.setFieldsValue({ attrList: props.values }); | |||
} | |||
} | |||
}, [props.values]); | |||
const toggleContent = (key) => { | |||
if (expandedCardKeys.includes(key)) { | |||
setExpandedCardKeys(expandedCardKeys.filter(k => k !== key)); | |||
} else { | |||
setExpandedCardKeys([...expandedCardKeys, key]); | |||
} | |||
}; | |||
const handleInputChange = (e, field) => { | |||
const updatedValues = [...inputValues]; | |||
updatedValues[field.key] = { ...updatedValues[field.key], value: e.target.value }; | |||
setInputValues(updatedValues); | |||
}; | |||
return ( | |||
<Modal | |||
key={Date.now} | |||
title={props.values.id ? '编辑配方' : '新建配方'} | |||
width={700} | |||
bodyStyle={{ padding: '32px 40px 1px 48px' }} | |||
visible={props.modalVisible} | |||
onCancel={props.onCancel} | |||
footer={null} | |||
maskClosable={false} | |||
destroyOnClose={true} | |||
> | |||
<Form | |||
labelCol={{ | |||
span: 6, | |||
}} | |||
wrapperCol={{ | |||
span: 18, | |||
}} | |||
form={form} | |||
name="" | |||
style={{ | |||
maxWidth: 700, | |||
}} | |||
autoComplete="off" | |||
onFinish={props.onFinish} | |||
> | |||
<Form.List name="attrList"> | |||
{(fields, { add, remove }) => ( | |||
<div | |||
style={{ | |||
display: 'flex', | |||
rowGap: 16, | |||
flexDirection: 'column', | |||
}} | |||
> | |||
{fields.map((field) => { | |||
const attrId = props.values[field.key]?.id; | |||
return ( | |||
<ProCard | |||
size="small" | |||
title={((inputValues[field?.key]?.value == undefined ? '' : inputValues[field?.key]?.value)) + (!expandedCardKeys.includes(field.key) ? '(点击收缩)' : '(点击展开)')} | |||
key={field.key} | |||
type='inner' | |||
headerBordered | |||
bordered | |||
collapsible | |||
onClick={() => toggleContent(field.key)} | |||
extra={ | |||
<CloseOutlined | |||
onClick={(e) => { | |||
e.stopPropagation(); | |||
if (attrId == undefined) { | |||
remove(field.name) | |||
message.success("删除成功") | |||
} else { | |||
api.deleteRecipeAttribute(attrId, 1).then((r) => { | |||
if (r.data) { | |||
message.success("删除成功") | |||
remove(field.name) | |||
} else { | |||
message.error("删除失败:该属性已被使用!") | |||
} | |||
}) | |||
} | |||
}} | |||
/> | |||
} | |||
> | |||
{!expandedCardKeys.includes(field.key) && ( | |||
<div onClick={(e) => e.stopPropagation()}> | |||
<Form.Item label="属性名称" name={[field.name, 'name']} rules={[{ required: true, max: 50 }]} style={{ display: 'inline-block', width: '50%' }}> | |||
<Input placeholder="属性名称" onChange={(e) => handleInputChange(e, field)} /> | |||
</Form.Item> | |||
<Form.Item label="序号" name={[field.name, 'sort']} rules={[{ required: true }]} style={{ display: 'inline-block', width: '50%' }}> | |||
<InputNumber placeholder="序号" /> | |||
</Form.Item> | |||
<Form.Item label="属性值" rules={[{ required: true, max: 50 }]} style={{ display: 'inline-block', width: '100%', marginLeft: '-12.5%' }}> | |||
<Form.List name={[field.name, 'valueList']}> | |||
{(subFields, subOpt) => ( | |||
<div | |||
style={{ | |||
display: 'flex', | |||
flexDirection: 'column', | |||
rowGap: 16, | |||
}} | |||
> | |||
{subFields.map((subField) => { | |||
const valueId = props.values[field.key]?.valueList[subField.key]?.id; | |||
return ( | |||
<Space key={subField.key}> | |||
<Form.Item noStyle name={[subField.name, 'name']}> | |||
<Input placeholder="属性值" /> | |||
</Form.Item> | |||
<Form.Item noStyle name={[subField.name, 'sort']}> | |||
<Input placeholder="序号" /> | |||
</Form.Item> | |||
<CloseOutlined | |||
onClick={() => { | |||
if (attrId == undefined) { | |||
message.success("删除成功") | |||
subOpt.remove(subField.name) | |||
} else { | |||
api.deleteRecipeAttribute(valueId, 2).then((r) => { | |||
if (r.data) { | |||
message.success("删除成功") | |||
subOpt.remove(subField.name) | |||
} else { | |||
message.error("删除失败:该属性值已被使用!") | |||
} | |||
}) | |||
} | |||
}} | |||
/> | |||
</Space> | |||
) | |||
})} | |||
<Button type="dashed" block onClick={() => { | |||
var currentValueList = form.getFieldValue(['attrList', field.name, 'valueList']) || []; | |||
var maxSort = currentValueList.length > 0 ? Math.max(...currentValueList.map(item => item.sort || 0)) : 0; | |||
subOpt.add({ sort: maxSort + 1 }); | |||
}}> | |||
添加属性值 | |||
</Button> | |||
</div> | |||
)} | |||
</Form.List> | |||
</Form.Item> | |||
</div> | |||
)} | |||
</ProCard> | |||
) | |||
})} | |||
<Button type="dashed" block onClick={() => { | |||
var maxSort = 0; | |||
if (fields.length != 0) { | |||
maxSort = Math.max(...fields.map(field => form.getFieldValue(['attrList', field.name, 'sort']) || 0)); | |||
} | |||
add({ sort: maxSort + 1 }); | |||
}}> | |||
添加属性 | |||
</Button> | |||
</div> | |||
)} | |||
</Form.List> | |||
<br /> | |||
<Form.Item style={{ marginLeft: '72%', marginRight: '-7%' }}> | |||
<Button htmlType="button" style={{ float: 'right', left: 10 }} onClick={props.onCancel} > | |||
取消 | |||
</Button> | |||
<Button type="primary" htmlType="submit" style={{ float: 'right' }} > | |||
保存 | |||
</Button> | |||
</Form.Item> | |||
</Form> | |||
</Modal> | |||
) | |||
} | |||
export default CreateAttrForm; |
@@ -0,0 +1,56 @@ | |||
import { Modal, Form, Button, Input, InputNumber, TreeSelect } from 'antd'; | |||
const CreateForm = (props) => { | |||
return ( | |||
<Modal | |||
title={props.values.id ? '编辑分组' : '新建分组'} | |||
width={640} | |||
bodyStyle={{ padding: '32px 40px 1px 48px' }} | |||
visible={props.modalVisible} | |||
onCancel={props.onCancel} | |||
footer={null} | |||
maskClosable={false} | |||
destroyOnClose | |||
> | |||
<Form | |||
layout="horizontal" | |||
preserve={false} | |||
labelCol={{ | |||
span: 4, | |||
}} | |||
initialValues={props.values} | |||
onFinish={props.onFinish} | |||
> | |||
<Form.Item name="id" hidden={true}> | |||
<Input /> | |||
</Form.Item> | |||
<Form.Item name="name" label="分组名称" rules={[{ required: true }]}> | |||
<Input placeholder='请输入分组名称'/> | |||
</Form.Item> | |||
<Form.Item name="isWeight" label="分组模式" rules={[{ required: true }]}> | |||
<TreeSelect | |||
style={{ width: '100%' }} | |||
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }} | |||
treeData={props.isWeightList} | |||
placeholder="请选择是否称重" | |||
treeDefaultExpandAll | |||
allowClear | |||
/> | |||
</Form.Item> | |||
<Form.Item name="sort" label="排序"> | |||
<InputNumber /> | |||
</Form.Item> | |||
<Form.Item> | |||
<Button htmlType="button" style={{ float: 'right', left: 10 }} onClick={props.onCancel}> | |||
取消 | |||
</Button> | |||
<Button type="primary" htmlType="submit" style={{ float: 'right' }}> | |||
保存 | |||
</Button> | |||
</Form.Item> | |||
</Form> | |||
</Modal> | |||
) | |||
} | |||
export default CreateForm; |
@@ -0,0 +1,393 @@ | |||
import { Button, Modal, Radio, Tag, message, Popconfirm, InputNumber } from 'antd'; | |||
import { ProCard } from '@ant-design/pro-Card'; | |||
import ProTable, { EditableProTable } from '@ant-design/pro-table'; | |||
import api from '../service'; | |||
import { useEffect, useRef, useState } from 'react'; | |||
import CreateAttrForm from './CreateAttrForm'; | |||
const RecipeDetailForm = (props) => { | |||
const actionRef = useRef() | |||
const [recipeAttrFormList, setRecipeAttrFormList] = useState([]) | |||
const [recipeAttrList, setRecipeAttrList] = useState([]) | |||
const [attrModalVisible, handleModalVisible] = useState(false) | |||
const [batchingList, setBatchingList] = useState([]) | |||
const [editableKeys, setEditableRowKeys] = useState([]) | |||
const [valueIds, setValueIds] = useState('') | |||
const [names, setNames] = useState('') | |||
useEffect(() => { | |||
getRecipeAttrList(); | |||
getBaseBatchingList(); | |||
}, []); | |||
const getRecipeAttrList = async () => { | |||
if (props.values?.id != undefined) { | |||
var data = await api.getRecipeAttributeList(props.values.id); | |||
setRecipeAttrList(data.data); | |||
} | |||
} | |||
const getBaseBatchingList = async () => { | |||
if (props.values?.id != undefined) { | |||
var data = await api.getBaseBatchingList(props.values.id); | |||
setEditableRowKeys(data.data.map((item) => item.id)); | |||
setBatchingList(data.data); | |||
} | |||
} | |||
const getAttrBatchingList = async (valueIds) => { | |||
var data = await api.getAttrBatchingList(props.values.id, valueIds); | |||
setEditableRowKeys(data.data.map((item) => item.id)); | |||
setBatchingList(data.data); | |||
} | |||
const setRecipeBatching = async () => { | |||
if (valueIds != '') { | |||
var valueCount = valueIds.split(',').length; | |||
var attrCount = recipeAttrList.length; | |||
if (valueCount != attrCount) { | |||
message.error("属性未勾选完整") | |||
return; | |||
} | |||
} | |||
var data = {}; | |||
data.batchingList = batchingList; | |||
data.recipeId = props.values.id; | |||
data.valueIds = valueIds == '' ? null : valueIds; | |||
await api.setRecipeBatching(data).then((r) => { | |||
if (r.data) { | |||
message.success("保存成功"); | |||
} else { | |||
message.error(r.errors) | |||
} | |||
actionRef.current.reload() | |||
}) | |||
} | |||
const onChangevalue = (e) => { | |||
const { value } = e.target; | |||
var valueIdList = []; | |||
var nameList = []; | |||
var newId = null; | |||
recipeAttrList.forEach(item => { | |||
item.valueList.forEach(x => { | |||
if (x.id == value) { | |||
newId = x.attributeId; | |||
} | |||
}) | |||
}) | |||
recipeAttrList.forEach(item => { | |||
if (item.id == newId) { | |||
item.valueList.forEach(x => { | |||
if (x.id == value) { | |||
item.defalutvalue = value; | |||
} | |||
} | |||
) | |||
} | |||
}) | |||
recipeAttrList.forEach(x => { | |||
if (x.defalutvalue != undefined) { | |||
valueIdList.push(x.defalutvalue); | |||
} | |||
var name = x.valueList.find(t => t.id == x.defalutvalue)?.name; | |||
if (name != undefined) { | |||
nameList.push(name); | |||
} | |||
}) | |||
var valueIds = valueIdList.join(','); | |||
setValueIds(valueIds); | |||
var names = nameList.join('-'); | |||
setNames(names); | |||
setRecipeAttrList(recipeAttrList); | |||
setBatchingList([]); | |||
getAttrBatchingList(valueIds); | |||
actionRef.current.reload(); | |||
} | |||
const cleanAttr = () => { | |||
setBatchingList([]); | |||
setValueIds(''); | |||
recipeAttrList.forEach(item => { | |||
item.defalutvalue = null; | |||
}) | |||
setRecipeAttrList(recipeAttrList); | |||
actionRef.current.reload(); | |||
} | |||
const deleteRecipeAttr = (id) => { | |||
api.deleteRecipeAttr(id).then((r) => { | |||
if (r.data) { | |||
message.success("删除成功") | |||
} else { | |||
message.error(r.errors) | |||
} | |||
if (valueIds != '') { | |||
setBatchingList([]); | |||
} | |||
actionRef.current.reload(); | |||
}) | |||
} | |||
const editAttrRecipe = (item) => { | |||
recipeAttrList.forEach(t => { | |||
t.valueList.forEach(x => { | |||
if (item.valueIds.includes(x.id)) { | |||
t.defalutvalue = x.id; | |||
} | |||
}) | |||
}) | |||
setValueIds(item.valueIds); | |||
setNames(item.name); | |||
setRecipeAttrList(recipeAttrList); | |||
setBatchingList(item.batchingList); | |||
setEditableRowKeys(item.batchingList.map((i) => i.id)); | |||
} | |||
const setBaseBatchingList = async () => { | |||
var data = await api.getBaseBatchingList(props.values.id); | |||
setEditableRowKeys(data.data.map((item) => item.id)); | |||
setBatchingList(data.data); | |||
} | |||
const columns = [ | |||
{ | |||
title: '主键', | |||
dataIndex: 'id', | |||
key: 'id', | |||
hideInTable: true, | |||
hideInSearch: true, | |||
tip: '规则名称是唯一的 key', | |||
}, | |||
{ | |||
title: '物料Id', | |||
dataIndex: 'batchingId', | |||
hideInTable: true, | |||
hideInSearch: true | |||
}, | |||
{ | |||
title: '物料名称', | |||
dataIndex: 'name', | |||
hideInSearch: true, | |||
editable: false | |||
}, | |||
{ | |||
title: '用量(g)', | |||
dataIndex: 'weight', | |||
valueType: 'digit', | |||
hideInSearch: true, | |||
editable: true | |||
} | |||
] | |||
const listColumns = [ | |||
{ | |||
title: '主键', | |||
dataIndex: 'id', | |||
key: 'id', | |||
hideInTable: true, | |||
hideInSearch: true, | |||
tip: '规则名称是唯一的 key', | |||
}, | |||
{ | |||
title: '多属性名称', | |||
dataIndex: 'name', | |||
hideInSearch: true | |||
}, | |||
{ | |||
title: '操作', | |||
dataIndex: 'option', | |||
valueType: 'option', | |||
fixed: 'right', | |||
render: (_, record) => [ | |||
<a | |||
key="primary" | |||
type="primary" | |||
onClick={() => { editAttrRecipe(record) }} | |||
>编辑</a>, | |||
<Popconfirm | |||
type="primary" | |||
key="primary" | |||
title="确认删除吗?" | |||
okText="是" | |||
cancelText="否" | |||
onConfirm={() => { deleteRecipeAttr(record.id) }} | |||
onCancel | |||
> | |||
<a href="#">删除</a> | |||
</Popconfirm> | |||
] | |||
}, | |||
] | |||
return ( | |||
<Modal | |||
title={props.values.name} | |||
width={1300} | |||
bodyStyle={{ padding: '32px 40px 10px 48px' }} | |||
visible={props.detailModalOpen} | |||
onCancel={props.onCancel} | |||
footer={null} | |||
maskClosable={false} | |||
destroyOnClose | |||
> | |||
<ProCard split="vertical" style={{ height: '700px' }} > | |||
<div style={{ width: '50%', borderRight: '1px solid #f0f0f0' }}> | |||
<div style={{ height: '40%' }}> | |||
<ProCard | |||
title='属性' | |||
type='inner' | |||
colSpan="50%" | |||
height='50%' | |||
> | |||
<Button | |||
type="primary" | |||
key="primary" | |||
onClick={() => { | |||
setRecipeAttrFormList(recipeAttrList) | |||
handleModalVisible(true) | |||
}} | |||
> | |||
编辑属性 | |||
</Button> | |||
<Button | |||
type="primary" | |||
key="primary" | |||
style={{ marginLeft: 10 }} | |||
onClick={() => { | |||
getBaseBatchingList() | |||
cleanAttr() | |||
}} | |||
> | |||
查看基础配方 | |||
</Button> | |||
<Button | |||
type="dashed" | |||
style={{ float: 'right' }} | |||
onClick={() => { cleanAttr() }} | |||
> | |||
清空选择 | |||
</Button> | |||
<div style={{ marginTop: 10, height:150, overflowY: 'auto' }}> | |||
{ | |||
recipeAttrList == "" ? (<div>点击“编辑属性”添加属性和属性值!</div>) : ( | |||
recipeAttrList.map((item, index) => { | |||
return ( | |||
<div style={{ marginTop: 10, width:'max-content', overflowX: 'auto' }}> | |||
<span><Tag color="blue">{item.name}</Tag>:</span> | |||
<span> | |||
<Radio.Group name={index} buttonStyle="solid" onChange={onChangevalue} value={item.defalutvalue}> | |||
{ | |||
item.valueList.map((x, i) => { | |||
return ( | |||
<Radio.Button key={i} name={i} value={x.id} style={{ marginLeft: 10 }}>{x.name}</Radio.Button> | |||
) | |||
}) | |||
} | |||
</Radio.Group> | |||
</span> | |||
</div> | |||
) | |||
}) | |||
) | |||
} | |||
</div> | |||
</ProCard> | |||
</div> | |||
<div style={{ height: '60%' }}> | |||
<ProTable | |||
headerTitle="列表" | |||
actionRef={actionRef} | |||
height='50%' | |||
search={false} | |||
pagination={{ defaultPageSize: 5 }} | |||
request={async () => { | |||
var data = []; | |||
await api.getAttrRecipeList(props.values.id, valueIds).then((r) => { | |||
data = r.data; | |||
}); | |||
return { | |||
data: data, | |||
success: true | |||
}; | |||
}} | |||
columns={listColumns} | |||
/> | |||
</div> | |||
</div> | |||
<ProCard | |||
title={'配方' + (props.isWeight ? "(基准克数:" + (props.values.referenceWeight == null ? '0' : props.values.referenceWeight) + ")" : '')} | |||
type='inner' | |||
colSpan="50%" | |||
> | |||
<div style={{ position: 'relative', height: 580, overflow: 'hidden' }}> | |||
<div style={{ position: 'sticky', height: 50, top: 0, backgroundColor: '#fff', zIndex: 10 }}> | |||
<span style={{ color: '#FA541C', fontSize: 15, marginLeft: 25, height: 50, width: 280, display: 'inline-block', overflowY: 'auto' }}> | |||
{valueIds === '' ? '基础配方' : names} | |||
</span> | |||
<div style={{ float: 'right' }}> | |||
{valueIds === '' ? ("") : ( | |||
<Button | |||
type="primary" | |||
key="primary" | |||
onClick={() => { setBaseBatchingList(); }} | |||
style={{ marginRight: '8px' }} | |||
> | |||
填入基础配方数据 | |||
</Button> | |||
)} | |||
<Button | |||
type="primary" | |||
key="save" | |||
onClick={() => { setRecipeBatching(); }} | |||
> | |||
保存数据 | |||
</Button> | |||
</div> | |||
</div> | |||
<EditableProTable | |||
columns={columns} | |||
rowKey="id" | |||
height='530' | |||
value={batchingList} | |||
onChange={setBatchingList} | |||
recordCreatorProps={false} | |||
style={{ overflowY: 'auto', height: 'calc(100% - 30px)' }} | |||
editable={{ | |||
type: 'multiple', | |||
editableKeys, | |||
onValuesChange: (record, recordList) => { | |||
setBatchingList(recordList); | |||
}, | |||
}} | |||
/> | |||
</div> | |||
</ProCard> | |||
</ProCard> | |||
<CreateAttrForm | |||
key={Date.now()} | |||
onFinish={async (value) => { | |||
handleModalVisible(false); | |||
setRecipeAttrFormList([]); | |||
value.attrList.forEach((item) => { | |||
item.recipeId = props.values.id | |||
}); | |||
await api.updateRecipeAttribute(value.attrList).then(r => { | |||
if (r.data) { | |||
if (value.attrList[0].id == undefined) { | |||
message.success("添加成功") | |||
} | |||
else { | |||
message.success("修改成功") | |||
} | |||
getRecipeAttrList() | |||
} | |||
else { | |||
message.error(r.errors) | |||
} | |||
}) | |||
}} | |||
onCancel={() => { | |||
getRecipeAttrList(); | |||
handleModalVisible(false); | |||
setRecipeAttrFormList([]); | |||
}} | |||
modalVisible={attrModalVisible} | |||
values={recipeAttrFormList || {}} | |||
/> | |||
</Modal> | |||
) | |||
} | |||
export default RecipeDetailForm; |
@@ -0,0 +1,197 @@ | |||
const buttonStyle = { | |||
width: '100%', | |||
height: '150px', | |||
textAlign: 'center', | |||
whiteSpace: 'normal' | |||
} | |||
const operateStyle = { | |||
position: 'absolute', | |||
top: '5%', | |||
right: '3%', | |||
border: 'none', | |||
background: 'transparent', | |||
cursor: 'pointer', | |||
color: '#FA541C', | |||
} | |||
import api from '../service'; | |||
import React, { useState, useEffect } from 'react'; | |||
import { Button, message, Popconfirm } from 'antd'; | |||
import { FormOutlined, CloseOutlined } from '@ant-design/icons'; | |||
import UpdateRecipeInfoForm from './UpdateRecipeInfoForm'; | |||
import RecipeDetailForm from './RecipeDetailForm'; | |||
const RecipeInfoForm = (props) => { | |||
const [modalVisible, handleModalVisible] = useState(false); | |||
const [recipeInfo, setRecipeInfo] = useState([]); | |||
const [filledValues, setFilledValues] = useState([]); | |||
const [detailModalOpen, handleDetailModalOpen] = useState(false); | |||
useEffect(() => { | |||
fillValues(props.values) | |||
}, [props.values]); | |||
function fillValues(list) { | |||
var values = []; | |||
if (list.length == 0) { | |||
values = Array.from({ length: 20 }, (_, index) => { | |||
return { | |||
id: "", | |||
recipeGroupId: "", | |||
name: '+', | |||
sort: index + 1 | |||
} | |||
}); | |||
} | |||
else { | |||
list.forEach(t => { | |||
if (t.name === "") { | |||
t.name = "+" | |||
} | |||
}) | |||
values = list; | |||
} | |||
setFilledValues(values) | |||
} | |||
const getRecipeInfo = async (groupId, current) => { | |||
var data = await api.getRecipeInfoList(groupId, current); | |||
fillValues(data.data); | |||
} | |||
const deleteRecipeInfo = async (id) => { | |||
await api.deleteRecipeInfo(id).then((r) => { | |||
if (r.data) { | |||
message.success('删除成功'); | |||
getRecipeInfo(props.groupId, props.current); | |||
} else { | |||
message.error(r.errors); | |||
} | |||
}); | |||
} | |||
return ( | |||
<div style={{ | |||
height: '90%', | |||
display: 'grid', | |||
gridTemplateColumns: 'repeat(5, 19%)', | |||
gridTemplateRows: 'repeat(4, 25%)', | |||
gap: '10px', | |||
justifyContent: 'center', | |||
alignItems: 'center' | |||
}}> | |||
{filledValues.map((item, index) => ( | |||
<Button | |||
onClick={() => { | |||
if (props.groupId == undefined) { | |||
message.error("请先选择一个配方分组"); | |||
} | |||
else { | |||
setRecipeInfo(item) | |||
if (item.name === '+' || item.name === "") { | |||
handleModalVisible(true) | |||
} else { | |||
handleDetailModalOpen(true) | |||
} | |||
} | |||
}} | |||
key={index} | |||
style={{ | |||
...buttonStyle, | |||
border: (item.name === '+' || item.name === "") ? '1px dashed #FA541C' : '1px solid #FA541C', | |||
backgroundColor: (item.name === '+' || item.name === "") ? '#ffffff' : '#fff2e8' | |||
}} | |||
> | |||
{item.name != '+' && ( | |||
<span | |||
style={{ | |||
...operateStyle | |||
}} | |||
> | |||
<a | |||
onClick={(e) => { | |||
e.stopPropagation() | |||
setRecipeInfo(item) | |||
handleModalVisible(true) | |||
}} | |||
> | |||
<FormOutlined /> | |||
</a> | |||
<a | |||
onClick={(e) => { | |||
e.stopPropagation() | |||
}} | |||
style={{ marginLeft: 5 }} | |||
> | |||
<Popconfirm | |||
title="确认删除吗?" | |||
onConfirm={() => deleteRecipeInfo(item.id)} | |||
okText="确定" | |||
cancelText="取消" | |||
> | |||
<CloseOutlined /> | |||
</Popconfirm> | |||
</a> | |||
</span> | |||
)} | |||
{item.name} | |||
</Button> | |||
))} | |||
<UpdateRecipeInfoForm | |||
onFinish={async (value) => { | |||
setRecipeInfo([]); | |||
handleModalVisible(false); | |||
value.isWeight = props.isWeight; | |||
value.recipeGroupId = props.groupId; | |||
await api.updateRecipeInfo(value).then(r => { | |||
if (r.data) { | |||
if (value.id == undefined) { | |||
message.success("添加成功") | |||
} | |||
else { | |||
message.success("修改成功") | |||
} | |||
getRecipeInfo(props.groupId, props.current) | |||
} | |||
else { | |||
if (recipeInfo.name === "") { | |||
filledValues.forEach(t => { | |||
if (t.sort == recipeInfo.sort) { | |||
t.name = '+'; | |||
} | |||
}) | |||
setFilledValues(filledValues); | |||
} | |||
message.error(r.errors) | |||
} | |||
}) | |||
}} | |||
onCancel={() => { | |||
handleModalVisible(false); | |||
setRecipeInfo([]); | |||
if (recipeInfo.name === "") { | |||
filledValues.forEach(t => { | |||
if (t.sort == recipeInfo.sort) { | |||
t.name = '+'; | |||
} | |||
}) | |||
setFilledValues(filledValues); | |||
} | |||
}} | |||
modalVisible={modalVisible} | |||
isWeight={props.isWeight} | |||
values={recipeInfo || {}} | |||
/> | |||
<RecipeDetailForm | |||
key={Date.now()} | |||
onCancel={() => { | |||
getRecipeInfo(props.groupId, props.current); | |||
handleDetailModalOpen(false) | |||
setRecipeInfo([]) | |||
}} | |||
values={recipeInfo} | |||
isWeight={props.isWeight} | |||
detailModalOpen={detailModalOpen} | |||
/> | |||
</div> | |||
); | |||
}; | |||
export default RecipeInfoForm; |
@@ -0,0 +1,57 @@ | |||
import React, { useEffect } from 'react'; | |||
import { Modal, Form, Button, Input, InputNumber } from "antd"; | |||
const UpdateRecipeInfoForm = (props) => { | |||
useEffect(() => { | |||
if (props.values.name === '+') { | |||
props.values.name = ''; | |||
} | |||
}, [props.values, props.modalVisible]); | |||
return ( | |||
<Modal | |||
title={props.values.id ? '编辑配方' : '新建配方'} | |||
width={640} | |||
bodyStyle={{ padding: '32px 40px 1px 48px' }} | |||
visible={props.modalVisible} | |||
onCancel={props.onCancel} | |||
footer={null} | |||
maskClosable={false} | |||
destroyOnClose | |||
> | |||
<Form | |||
layout="horizontal" | |||
preserve={false} | |||
labelCol={{ | |||
span: 4, | |||
}} | |||
initialValues={props.values} | |||
onFinish={props.onFinish} | |||
> | |||
<Form.Item name="id" hidden={true}> | |||
<Input /> | |||
</Form.Item> | |||
<Form.Item name="name" label="配方名称" rules={[{ required: true }]}> | |||
<Input placeholder='请输入配方名称' /> | |||
</Form.Item> | |||
{props.isWeight == 1 ? | |||
<Form.Item name="referenceWeight" label="基准克数"> | |||
<InputNumber /> | |||
</Form.Item> : ""} | |||
<Form.Item name="sort" label="排序"> | |||
<InputNumber disabled/> | |||
</Form.Item> | |||
<Form.Item> | |||
<Button htmlType="button" style={{ float: 'right', left: 10 }} onClick={props.onCancel}> | |||
取消 | |||
</Button> | |||
<Button type="primary" htmlType="submit" style={{ float: 'right' }}> | |||
保存 | |||
</Button> | |||
</Form.Item> | |||
</Form> | |||
</Modal> | |||
) | |||
} | |||
export default UpdateRecipeInfoForm; |
@@ -0,0 +1,279 @@ | |||
import React, { useState, useEffect } from 'react'; | |||
import { PlusOutlined, FormOutlined, DeleteOutlined, CloseOutlined } from '@ant-design/icons'; | |||
import { PageContainer } from '@ant-design/pro-layout'; | |||
import { Button, message, Popconfirm, Pagination, Switch } from 'antd'; | |||
import { ProCard } from '@ant-design/pro-Card'; | |||
import api from './service'; | |||
import CreateForm from './components/CreateForm'; | |||
import RecipeInfoForm from './components/RecipeInfoForm'; | |||
const recipeinfo = () => { | |||
const [isWeight, setIsWeight] = useState(false); | |||
const [groupData, setGroupData] = useState([]); | |||
const [createModalVisible, handleModalVisible] = useState(); | |||
const [recipeGroupValues, setRecipeGroupValues] = useState([]); | |||
const [recipeInfoValues, setRecipeInfoValues] = useState([]); | |||
const [groupId, setGroupId] = useState(); | |||
const [current, setCurrent] = useState(1); | |||
const [defaultCurrent, setDefaultCurrent] = useState(1); | |||
const [total, setTotal] = useState(20); | |||
const isWeightList = [ | |||
{ value: false, label: '标准模式' }, | |||
{ value: true, label: '称重模式' }, | |||
]; | |||
useEffect(() => { | |||
initGroupList(false); | |||
}, []); | |||
const initGroupList = async (isWeight) => { | |||
var data = await api.getRecipeGroupList(isWeight); | |||
setGroupData(data.data); | |||
} | |||
const deleteGroup = async (id) => { | |||
await api.deleteRecipeGroup(id).then((r) => { | |||
if (r.data) { | |||
message.success('删除成功'); | |||
initGroupList(isWeight); | |||
setGroupId(); | |||
} else { | |||
message.error(r.errors); | |||
} | |||
}); | |||
} | |||
const getRecipeCount = async (id) => { | |||
var data = await api.getRecipeCount(id); | |||
var total = data.data; | |||
if (total === 0) { | |||
total = 20 | |||
} | |||
setTotal(total); | |||
} | |||
const getRecipeInfo = async (groupId, current) => { | |||
var data = await api.getRecipeInfoList(groupId, current); | |||
setRecipeInfoValues(data.data); | |||
} | |||
const addRecipePage = async () => { | |||
if(groupId === undefined){ | |||
message.error("请先选择一个配方分组"); | |||
}else{ | |||
var data = {}; | |||
data.recipeGroupId = groupId; | |||
await api.addRecipePage(data); | |||
var curr = total + 20; | |||
setTotal(curr) | |||
var current = Math.ceil(curr / 20); | |||
setCurrent(current) | |||
onChangepage(current) | |||
} | |||
} | |||
const deleteRecipePage = async () => { | |||
if(groupId === undefined){ | |||
message.error("请先选择一个配方分组"); | |||
}else{ | |||
await api.deleteRecipePage(groupId, current).then((r) => { | |||
if (r.data) { | |||
message.success('删除成功') | |||
changeGroup(groupId) | |||
} else { | |||
message.error(r.errors); | |||
} | |||
}) | |||
} | |||
} | |||
const onChangepage = (pageNumber) => { | |||
setCurrent(pageNumber) | |||
setDefaultCurrent(pageNumber) | |||
getRecipeInfo(groupId, pageNumber) | |||
}; | |||
const changeGroup = async (id) => { | |||
setCurrent(1) | |||
setDefaultCurrent(1) | |||
setGroupId(id) | |||
getRecipeCount(id) | |||
getRecipeInfo(id, 1) | |||
} | |||
const switchOnChange = (checked) => { | |||
if (checked) { | |||
setIsWeight(true); | |||
} else { | |||
setIsWeight(false); | |||
} | |||
initGroupList(checked); | |||
setGroupId(); | |||
setRecipeInfoValues([]); | |||
} | |||
return ( | |||
<PageContainer | |||
header={{ | |||
title: '', | |||
breadcrumb: {}, | |||
}} | |||
> | |||
<ProCard style={{ height: '700px' }} split="vertical"> | |||
<ProCard | |||
title='配方分组' | |||
type='inner' | |||
colSpan="25%" | |||
style={{ height: '800px', overflowY: 'auto' }} | |||
headStyle={{ position: 'sticky', top: 0, background: 'white', zIndex: 1 }} | |||
extra={ | |||
<Button | |||
type="default" | |||
block | |||
ghost | |||
onClick={() => { | |||
handleModalVisible(true); | |||
}} | |||
style={{ | |||
float: 'right', | |||
background: '#FA541C' | |||
}}> | |||
<PlusOutlined />添加分组 | |||
</Button> | |||
} | |||
> | |||
<Switch | |||
checkedChildren="称重模式" | |||
unCheckedChildren="标准模式" | |||
defaultunChecked | |||
onChange={switchOnChange} | |||
style={{ | |||
marginTop: -10, | |||
marginBottom: 10, | |||
backgroundColor: '#FA541C', | |||
borderColor: '#FA541C', | |||
}} | |||
checkedStyle={{ | |||
backgroundColor: '#FA541C', | |||
borderColor: '#FA541C', | |||
}} | |||
unCheckedStyle={{ | |||
backgroundColor: '#FA541C', | |||
borderColor: '#FA541C', | |||
}} | |||
/> | |||
<div> | |||
{ | |||
groupData.length > 0 ? groupData.map(x => { | |||
const isSelected = x.id === groupId; | |||
return ( | |||
<ProCard | |||
boxShadow | |||
hoverable | |||
bordered | |||
key={x.id} | |||
onClick={() => { changeGroup(x.id) }} | |||
bodyStyle={{ padding: 15, display: 'flex', justifyContent: 'center' }} | |||
headStyle={{ padding: '0px 24px' }} | |||
style={{ | |||
marginBlockEnd: 8, | |||
boxShadow: isSelected ? '-1px 5px 5px gray' : undefined, | |||
borderColor: isSelected ? 'gray' : undefined, | |||
borderWidth: '1px', | |||
borderStyle: 'solid' | |||
}} | |||
extra={ | |||
<div> | |||
<FormOutlined | |||
onClick={() => { | |||
setRecipeGroupValues(x) | |||
handleModalVisible(true) | |||
}} | |||
/> | |||
<Popconfirm | |||
title="确认删除吗?" | |||
onConfirm={() => deleteGroup(x.id)} | |||
okText="确定" | |||
cancelText="取消" | |||
> | |||
<DeleteOutlined style={{ marginLeft: 10 }} /> | |||
</Popconfirm> | |||
</div> | |||
} | |||
> | |||
<p>{x.name}</p> | |||
</ProCard> | |||
) | |||
}) : <div>点击添加分组按钮添加配方分组!</div> | |||
} | |||
</div> | |||
</ProCard> | |||
<ProCard | |||
type='inner' | |||
title='配方' | |||
style={{ height: '800px' }} | |||
> | |||
<div style={{ height:'100%', overflow: 'hidden', clear: 'both' }}> | |||
{ | |||
<RecipeInfoForm values={recipeInfoValues} current={current} groupId={groupId} isWeight={isWeight} /> | |||
} | |||
<div style={{ textAlign: 'center', marginTop: 35 }}> | |||
<Pagination | |||
style={{ display: 'inline-flex' }} | |||
current={current} | |||
defaultPageSize={20} | |||
defaultCurrent={defaultCurrent} | |||
total={total} | |||
onChange={onChangepage} | |||
showSizeChanger={false} | |||
/> | |||
<Button | |||
type="primary" | |||
style={{ marginLeft: 10 }} | |||
onClick={() => addRecipePage()} | |||
> | |||
<PlusOutlined />新增页 | |||
</Button> | |||
<Popconfirm | |||
title="删除当前页及其配方?" | |||
onConfirm={() => deleteRecipePage()} | |||
okText="确定" | |||
cancelText="取消" | |||
> | |||
<Button | |||
type="primary" | |||
style={{ marginLeft: 10 }} | |||
> | |||
<CloseOutlined />删除当前页 | |||
</Button> | |||
</Popconfirm> | |||
</div> | |||
</div> | |||
</ProCard> | |||
</ProCard> | |||
<CreateForm | |||
onFinish={async (value) => { | |||
setRecipeGroupValues([]); | |||
handleModalVisible(false); | |||
await api.updataRecipeGroup(value).then(r => { | |||
if (r.data) { | |||
if (value.id == undefined) { | |||
message.success("添加成功") | |||
} | |||
else { | |||
message.success("修改成功") | |||
} | |||
initGroupList(isWeight); | |||
} | |||
else { | |||
message.error(r.errors) | |||
} | |||
}) | |||
setGroupId(); | |||
}} | |||
onCancel={() => { | |||
handleModalVisible(false); | |||
setRecipeGroupValues([]); | |||
setGroupId(); | |||
}} | |||
modalVisible={createModalVisible} | |||
values={recipeGroupValues || {}} | |||
isWeightList={isWeightList} | |||
/> | |||
</PageContainer> | |||
) | |||
} | |||
export default recipeinfo; |
@@ -0,0 +1,94 @@ | |||
import { request } from 'umi'; | |||
import { getDataBaseUrl } from '@/global_data'; | |||
export default { | |||
getRecipeGroupList(isWeight) { | |||
return request(getDataBaseUrl() + `/api/recipe/getRecipeGroupList?isWeight=${isWeight}`, { | |||
method: 'Get', | |||
}); | |||
}, | |||
updataRecipeGroup(data) { | |||
return request(getDataBaseUrl() + `/api/recipe/updataRecipeGroup`, { | |||
method: 'Post', | |||
data: data, | |||
}); | |||
}, | |||
deleteRecipeGroup(data) { | |||
return request(getDataBaseUrl() + `/api/recipe/deleteRecipeGroup?id=${data}`, { | |||
method: 'Get', | |||
}); | |||
}, | |||
getRecipeCount(id) { | |||
return request(getDataBaseUrl() + `/api/recipe/GetRecipeCount?recipeGroupId=${id}`, { | |||
method: 'Get', | |||
}); | |||
}, | |||
getRecipeInfoList(id, page) { | |||
return request(getDataBaseUrl() + `/api/recipe/getRecipeInfoList?recipeGroupId=${id}&page=${page}`, { | |||
method: 'Get', | |||
}); | |||
}, | |||
updateRecipeInfo(data) { | |||
return request(getDataBaseUrl() + `/api/recipe/updateRecipeInfo`, { | |||
method: 'Post', | |||
data: data, | |||
}); | |||
}, | |||
deleteRecipeInfo(id) { | |||
return request(getDataBaseUrl() + `/api/recipe/deleteRecipeInfo?id=${id}`, { | |||
method: 'Get', | |||
}); | |||
}, | |||
getRecipeAttributeList(id) { | |||
return request(getDataBaseUrl() + `/api/recipeAttribute/getRecipeAttributeList?recipeId=${id}`, { | |||
method: 'Get', | |||
}); | |||
}, | |||
updateRecipeAttribute(data) { | |||
return request(getDataBaseUrl() + `/api/recipeAttribute/updateRecipeAttribute`, { | |||
method: 'Post', | |||
data: data, | |||
}); | |||
}, | |||
deleteRecipeAttribute(id, type) { | |||
return request(getDataBaseUrl() + `/api/recipeAttribute/deleteRecipeAttribute?id=${id}&type=${type}`, { | |||
method: 'Get', | |||
}); | |||
}, | |||
getBaseBatchingList(recipeId) { | |||
return request(getDataBaseUrl() + `/api/recipe/getBaseBatchingList?recipeId=${recipeId}`, { | |||
method: 'Get', | |||
}); | |||
}, | |||
getAttrBatchingList(recipeId, attrIds) { | |||
return request(getDataBaseUrl() + `/api/recipe/getAttrBatchingList?recipeId=${recipeId}&attrIds=${attrIds}`, { | |||
method: 'Get', | |||
}); | |||
}, | |||
setRecipeBatching(data) { | |||
return request(getDataBaseUrl() + `/api/recipe/setRecipeBatching`, { | |||
method: 'Post', | |||
data: data, | |||
}); | |||
}, | |||
getAttrRecipeList(recipeId, valueIds) { | |||
return request(getDataBaseUrl() + `/api/recipe/getAttrRecipeList?recipeId=${recipeId}&valueIds=${valueIds}`, { | |||
method: 'Get', | |||
}); | |||
}, | |||
deleteRecipeAttr(configId) { | |||
return request(getDataBaseUrl() + `/api/recipe/deleteRecipeAttr?configId=${configId}`, { | |||
method: 'Get', | |||
}); | |||
}, | |||
addRecipePage(data) { | |||
return request(getDataBaseUrl() + `/api/recipe/addRecipePage`, { | |||
method: 'Post', | |||
data: data, | |||
}); | |||
}, | |||
deleteRecipePage(recipeGroupId, page) { | |||
return request(getDataBaseUrl() + `/api/recipe/deleteRecipePage?recipeGroupId=${recipeGroupId}&page=${page}`, { | |||
method: 'Get', | |||
}); | |||
}, | |||
} |
@@ -0,0 +1,139 @@ | |||
import { PageContainer } from "@ant-design/pro-layout"; | |||
import { Tabs, Card, Input, DatePicker, Button } from "antd" | |||
import ProTable from '@ant-design/pro-table'; | |||
import React, { useState, useEffect } from 'react'; | |||
import moment from 'moment'; | |||
import api from "../service"; | |||
const { RangePicker } = DatePicker; | |||
const batchingreport = () =>{ | |||
const [tabIndex, setTabIndex] = useState(1); | |||
const [batchingName, setBatchingName] = useState(''); | |||
const [storeName, setStoreName] = useState(''); | |||
const [deviceName, setDeviceName] = useState(''); | |||
const [dataSource, setDataSource] = useState([]); | |||
const [timeRange, setTimeRange] = useState([ | |||
moment(moment(new Date(Date.now())).format('YYYY-MM-DD 00:00:00')), | |||
moment(moment(new Date(Date.now())).format('YYYY-MM-DD 23:59:59')), | |||
]); | |||
useEffect(() => { | |||
initData(); | |||
}, [tabIndex]); | |||
const initData = async () => { | |||
var data = []; | |||
if (tabIndex == 1) { | |||
data = await api.getBatchingUseSummary({ "batchingName": batchingName, "startTime": timeRange[0]._i, "endTime": timeRange[1]._i, "storeName": storeName, "deviceName": deviceName }); | |||
} | |||
setDataSource(data.data) | |||
} | |||
const resetRequest = async () => { | |||
setBatchingName('') | |||
setStoreName('') | |||
setDeviceName('') | |||
var startDate = moment(new Date(Date.now())).format('YYYY-MM-DD 00:00:00'); | |||
var endDate = moment(new Date(Date.now())).format('YYYY-MM-DD 23:59:59'); | |||
setTimeRange([moment(startDate),moment(endDate)]) | |||
var data = [] | |||
if (tabIndex == 1) { | |||
data = await api.getBatchingUseSummary({ "batchingName": "", "startTime": startDate, "endTime": endDate, "storeName": "", "deviceName": "" }); | |||
} | |||
setDataSource(data.data) | |||
} | |||
const summaryColumns = [ | |||
{ | |||
title: '主键', | |||
dataIndex: 'id', | |||
tip: 'key', | |||
hideInSearch: true, | |||
hideInTable: true | |||
}, | |||
{ | |||
title: '物料名称', | |||
dataIndex: 'batchingName', | |||
hideInSearch: true, | |||
ellipsis: true, | |||
}, | |||
{ | |||
title: '门店名称', | |||
dataIndex: 'storeName', | |||
hideInSearch: true, | |||
ellipsis: true, | |||
}, | |||
{ | |||
title: '设备名称', | |||
dataIndex: 'deviceName', | |||
hideInSearch: true, | |||
ellipsis: true, | |||
}, | |||
{ | |||
title: '使用数量', | |||
dataIndex: 'useWeight', | |||
hideInSearch: true, | |||
ellipsis: true, | |||
}, | |||
] | |||
return( | |||
<PageContainer | |||
header={{ | |||
title: '', | |||
breadcrumb: {}, | |||
}} | |||
> | |||
<Card style={{ marginBottom: 20 }}> | |||
<div style={{ display: 'flex', alignItems: 'center', width: '100%' }}> | |||
<span>物料名称:</span> | |||
<Input placeholder="请输入物料名称" style={{ width: '15%', margin: 10 }} value={batchingName} onChange={(a) => { setBatchingName(a.target.value) }} /> | |||
<span>门店名称:</span> | |||
<Input placeholder="请输入门店名称" style={{ width: '15%', margin: 10 }} value={storeName} onChange={(a) => { setStoreName(a.target.value) }} /> | |||
<span>设备名称:</span> | |||
<Input placeholder="请输入设备名称" style={{ width: '15%', margin: 10 }} value={deviceName} onChange={(a) => { setDeviceName(a.target.value) }} /> | |||
</div> | |||
<div style={{ display: 'flex', alignItems: 'center', width: '100%' }}> | |||
<span>使用时间:</span> | |||
<RangePicker showTime style={{ width: '25%', margin: 10 }} value={timeRange} onChange={(date, dateStrings) => { | |||
let tempDate = [ | |||
moment(moment(new Date(dateStrings[0])).format('YYYY-MM-DD HH:mm:ss')), | |||
moment(moment(new Date(dateStrings[1])).format('YYYY-MM-DD HH:mm:ss')), | |||
] | |||
setTimeRange(tempDate); | |||
}} /> | |||
<Button onClick={() => { resetRequest() }}> | |||
重置 | |||
</Button> | |||
<Button type="primary" style={{ marginLeft: 10 }} onClick={() => { initData() }}> | |||
查询 | |||
</Button> | |||
</div> | |||
</Card> | |||
<Card> | |||
<Tabs | |||
tabPosition={'left'} | |||
value={tabIndex} | |||
onChange={a => { setTabIndex(a) }} | |||
items={new Array(1).fill(null).map((_, i) => { | |||
const id = String(i + 1); | |||
return { | |||
label: '物料使用汇总', | |||
key: id, | |||
children: | |||
<ProTable | |||
headerTitle="物料使用汇总" | |||
rowKey="id" | |||
pagination={{ defaultPageSize: 10 }} | |||
search={false} | |||
toolBarRender={false} | |||
columns={summaryColumns} | |||
dataSource={dataSource} | |||
/> | |||
} | |||
})} | |||
/> | |||
</Card> | |||
</PageContainer> | |||
) | |||
} | |||
export default batchingreport; |
@@ -0,0 +1,188 @@ | |||
import { PageContainer } from "@ant-design/pro-layout"; | |||
import { Tabs, Card, Input, DatePicker, Button } from "antd" | |||
import ProTable from '@ant-design/pro-table'; | |||
import React, { useState, useEffect } from 'react'; | |||
import moment from 'moment'; | |||
import api from "../service"; | |||
const { RangePicker } = DatePicker; | |||
const recipereport = () => { | |||
const [tabIndex, setTabIndex] = useState(1); | |||
const [recipeName, setRecipeName] = useState(''); | |||
const [storeName, setStoreName] = useState(''); | |||
const [deviceName, setDeviceName] = useState(''); | |||
const [dataSource, setDataSource] = useState([]); | |||
const [timeRange, setTimeRange] = useState([ | |||
moment(moment(new Date(Date.now())).format('YYYY-MM-DD 00:00:00')), | |||
moment(moment(new Date(Date.now())).format('YYYY-MM-DD 23:59:59')), | |||
]); | |||
useEffect(() => { | |||
initData(); | |||
}, [tabIndex]); | |||
const initData = async () => { | |||
var data = []; | |||
if (tabIndex == 1) { | |||
data = await api.getRecipeUseDetail({ "recipeName": recipeName, "startTime": timeRange[0]._i, "endTime": timeRange[1]._i, "storeName": storeName, "deviceName": deviceName }); | |||
} else { | |||
data = await api.getRecipeUseSummary({ "recipeName": recipeName, "startTime": timeRange[0]._i, "endTime": timeRange[1]._i, "storeName": storeName, "deviceName": deviceName }); | |||
} | |||
setDataSource(data.data) | |||
} | |||
const resetRequest = async () => { | |||
setRecipeName('') | |||
setStoreName('') | |||
setDeviceName('') | |||
var startDate = moment(new Date(Date.now())).format('YYYY-MM-DD 00:00:00'); | |||
var endDate = moment(new Date(Date.now())).format('YYYY-MM-DD 23:59:59'); | |||
setTimeRange([moment(startDate),moment(endDate)]) | |||
var data = [] | |||
if (tabIndex == 1) { | |||
data = await api.getRecipeUseDetail({ "recipeName": "", "startTime": startDate, "endTime": endDate, "storeName": "", "deviceName": "" }); | |||
} else { | |||
data = await api.getRecipeUseSummary({ "recipeName": "", "startTime": startDate, "endTime": endDate, "storeName": "", "deviceName": "" }); | |||
} | |||
setDataSource(data.data) | |||
} | |||
const detailColumns = [ | |||
{ | |||
title: '主键', | |||
dataIndex: 'id', | |||
tip: 'key', | |||
hideInSearch: true, | |||
hideInTable: true | |||
}, | |||
{ | |||
title: '配方名称', | |||
dataIndex: 'recipeName', | |||
ellipsis: true, | |||
hideInSearch: true, | |||
}, | |||
{ | |||
title: '门店名称', | |||
dataIndex: 'storeName', | |||
ellipsis: true, | |||
hideInSearch: true, | |||
}, | |||
{ | |||
title: '设备名称', | |||
dataIndex: 'deviceName', | |||
ellipsis: true, | |||
hideInSearch: true, | |||
}, | |||
{ | |||
title: '使用时间', | |||
dataIndex: 'useDate', | |||
ellipsis: true, | |||
hideInSearch: true, | |||
}, | |||
] | |||
const summaryColumns = [ | |||
{ | |||
title: '主键', | |||
dataIndex: 'id', | |||
tip: 'key', | |||
hideInSearch: true, | |||
hideInTable: true | |||
}, | |||
{ | |||
title: '配方名称', | |||
dataIndex: 'recipeName', | |||
ellipsis: true, | |||
hideInSearch: true, | |||
}, | |||
{ | |||
title: '门店名称', | |||
dataIndex: 'storeName', | |||
ellipsis: true, | |||
hideInSearch: true, | |||
}, | |||
{ | |||
title: '设备名称', | |||
dataIndex: 'deviceName', | |||
ellipsis: true, | |||
hideInSearch: true, | |||
}, | |||
{ | |||
title: '使用数量', | |||
dataIndex: 'useCount', | |||
ellipsis: true, | |||
hideInSearch: true, | |||
}, | |||
] | |||
return ( | |||
<PageContainer | |||
header={{ | |||
title: '', | |||
breadcrumb: {}, | |||
}} | |||
> | |||
<Card style={{ marginBottom: 20 }}> | |||
<div style={{ display: 'flex', alignItems: 'center', width: '100%' }}> | |||
<span>配方名称:</span> | |||
<Input placeholder="请输入配方名称" style={{ width: '15%', margin: 10 }} value={recipeName} onChange={(a) => { setRecipeName(a.target.value) }} /> | |||
<span>门店名称:</span> | |||
<Input placeholder="请输入门店名称" style={{ width: '15%', margin: 10 }} value={storeName} onChange={(a) => { setStoreName(a.target.value) }} /> | |||
<span>设备名称:</span> | |||
<Input placeholder="请输入设备名称" style={{ width: '15%', margin: 10 }} value={deviceName} onChange={(a) => { setDeviceName(a.target.value) }} /> | |||
</div> | |||
<div style={{ display: 'flex', alignItems: 'center', width: '100%' }}> | |||
<span>使用时间:</span> | |||
<RangePicker showTime style={{ width: '25%', margin: 10 }} value={timeRange} onChange={(date, dateStrings) => { | |||
let tempDate = [ | |||
moment(moment(new Date(dateStrings[0])).format('YYYY-MM-DD HH:mm:ss')), | |||
moment(moment(new Date(dateStrings[1])).format('YYYY-MM-DD HH:mm:ss')), | |||
] | |||
setTimeRange(tempDate); | |||
}} /> | |||
<Button onClick={() => { resetRequest() }}> | |||
重置 | |||
</Button> | |||
<Button type="primary" style={{ marginLeft: 10 }} onClick={() => { initData() }}> | |||
查询 | |||
</Button> | |||
</div> | |||
</Card> | |||
<Card> | |||
<Tabs | |||
tabPosition={'left'} | |||
value={tabIndex} | |||
onChange={a => { setTabIndex(a) }} | |||
items={new Array(2).fill(null).map((_, i) => { | |||
const id = String(i + 1); | |||
return { | |||
label: id == 1 ? '配方使用明细' : '配方使用汇总', | |||
key: id, | |||
children: id == 1 ? | |||
<ProTable | |||
headerTitle="配方使用明细" | |||
rowKey="id" | |||
pagination={{ defaultPageSize: 10 }} | |||
search={false} | |||
toolBarRender={false} | |||
columns={detailColumns} | |||
dataSource={dataSource} | |||
/> | |||
: | |||
<ProTable | |||
headerTitle="配方使用汇总" | |||
rowKey="id" | |||
pagination={{ defaultPageSize: 10 }} | |||
search={false} | |||
toolBarRender={false} | |||
columns={summaryColumns} | |||
dataSource={dataSource} | |||
/> | |||
} | |||
})} | |||
/> | |||
</Card> | |||
</PageContainer> | |||
) | |||
} | |||
export default recipereport; |
@@ -0,0 +1,22 @@ | |||
import { request } from 'umi'; | |||
import { getDataBaseUrl } from '@/global_data'; | |||
export default { | |||
getRecipeUseDetail(params) { | |||
return request(getDataBaseUrl() + '/api/report/getRecipeUseDetail', { | |||
method: 'Post', | |||
data: params, | |||
}); | |||
}, | |||
getRecipeUseSummary(params) { | |||
return request(getDataBaseUrl() + '/api/report/getRecipeUseSummary', { | |||
method: 'Post', | |||
data: params, | |||
}); | |||
}, | |||
getBatchingUseSummary(params) { | |||
return request(getDataBaseUrl() + '/api/report/getBatchingUseSummary', { | |||
method: 'Post', | |||
data: params, | |||
}); | |||
}, | |||
} |
@@ -0,0 +1,63 @@ | |||
import { Modal, Form, TreeSelect, Button, Input } from 'antd'; | |||
const CreateForm = (props) => { | |||
const { TextArea } = Input; | |||
return ( | |||
<Modal | |||
title={props.values.id ? '编辑门店' : '新建门店'} | |||
width={640} | |||
bodyStyle={{ padding: '32px 40px 1px 48px' }} | |||
open={props.modalOpen} | |||
onCancel={props.onCancel} | |||
footer={null} | |||
maskClosable={false} | |||
destroyOnClose | |||
> | |||
<Form | |||
layout="horizontal" | |||
preserve={false} | |||
labelCol={{ | |||
span: 4, | |||
}} | |||
initialValues={props.values} | |||
onFinish={props.onFinish} | |||
> | |||
<Form.Item name="id" hidden={true}> | |||
<Input /> | |||
</Form.Item> | |||
<Form.Item name="name" label="门店名称" rules={[{ required: true }]}> | |||
<Input placeholder='请输入门店名称'/> | |||
</Form.Item> | |||
<Form.Item name="orgId" label="组织名称" rules={[{ required: false }]}> | |||
<TreeSelect | |||
style={{ width: '100%' }} | |||
dropdownStyle={{ maxHeight: 400, overflow: 'auto' }} | |||
treeData={props.treeData} | |||
placeholder="请选择组织名称" | |||
treeDefaultExpandAll | |||
allowClear | |||
/> | |||
</Form.Item> | |||
<Form.Item name="header" label="负责人"> | |||
<Input placeholder='请输入负责人'/> | |||
</Form.Item> | |||
<Form.Item name="phone" label="手机号"> | |||
<Input placeholder='请输入手机号'/> | |||
</Form.Item> | |||
<Form.Item name="description" label="描述"> | |||
<TextArea rows={4} rules={[{ max: 500 }]} /> | |||
</Form.Item> | |||
<Form.Item> | |||
<Button htmlType="button" style={{ float: 'right', left: 10 }} onClick={props.onCancel}> | |||
取消 | |||
</Button> | |||
<Button type="primary" htmlType="submit" style={{ float: 'right' }}> | |||
保存 | |||
</Button> | |||
</Form.Item> | |||
</Form> | |||
</Modal> | |||
) | |||
} | |||
export default CreateForm; |
@@ -0,0 +1,319 @@ | |||
import { PlusOutlined } from '@ant-design/icons'; | |||
import { Button, message, Popconfirm, Modal, Transfer, Select } from 'antd'; | |||
import React, { useState, useRef, useEffect } from 'react'; | |||
import { PageContainer } from '@ant-design/pro-layout'; | |||
import ProTable from '@ant-design/pro-table'; | |||
import CreateForm from './components/CreateForm'; | |||
import api from './service'; | |||
const storeinfo = () => { | |||
const actionRef = useRef(); | |||
const [createModalOpen, handleModalOpen] = useState(); | |||
const [stepFormValues, setStepFormValues] = useState({}); | |||
const [selectedRowsState, setSelectedRows] = useState(); | |||
const [isModalOpen, setIsModalOpen] = useState(false); | |||
const [treeData, setTreeData] = useState(); | |||
const [mockData, setMockData] = useState([]); | |||
const [targetKeys, setTargetKeys] = useState([]); | |||
const [storeId, setStoreId] = useState([]); | |||
const [hasDeviceRelation, setHasDeviceRelation] = useState(false); | |||
const [isWeight, setIsWeight] = useState(''); | |||
useEffect(() => { | |||
initOrg() | |||
getAllRecipeList(isWeight) | |||
}, []); | |||
function initOrg() { | |||
api.gettree().then((r) => { | |||
setTreeData(r.data); | |||
}); | |||
} | |||
function getAllRecipeList(isWeight) { | |||
api.getAllRecipeList(isWeight).then((item) => { | |||
var data = item.data; | |||
const tempMockData = []; | |||
data.forEach((item) => { | |||
tempMockData.push({ | |||
key: item.id, | |||
title: item.name, | |||
}); | |||
}) | |||
setMockData(tempMockData); | |||
}); | |||
} | |||
const getHasDeviceRelation = async (id) => { | |||
api.getHasDeviceRelation(id).then((r) => { | |||
setHasDeviceRelation(r.data) | |||
}) | |||
} | |||
const BatchDeletion = () => { | |||
return ( | |||
selectedRowsState?.length > 0 && | |||
( | |||
<Popconfirm | |||
title="确认删除吗?" | |||
onConfirm={onClickdele} | |||
okText="确定" | |||
cancelText="取消" | |||
> | |||
<Button type="primary">批量删除</Button> | |||
</Popconfirm> | |||
)) | |||
} | |||
const onClickdele = () => { | |||
handleRemove(selectedRowsState); | |||
setSelectedRows([]); | |||
actionRef.current?.reloadAndRest?.(); | |||
} | |||
const handleRemove = async (selectedRows) => { | |||
if (!selectedRows) return true; | |||
await api.deleteStore(selectedRows.map((row) => row.id)).then((r) => { | |||
if (r.data) { | |||
message.success('删除成功'); | |||
actionRef.current.reload(); | |||
} else { | |||
message.error(r.errors); | |||
} | |||
}); | |||
return true; | |||
}; | |||
const editStoreRecipe = async () => { | |||
const tempMockData = []; | |||
targetKeys.forEach(function (item, index, array) { | |||
tempMockData.push({ | |||
"recipeId": item | |||
}); | |||
}) | |||
var data = { | |||
"storeId": storeId, | |||
"recipeIdList": tempMockData | |||
} | |||
api.setStoreRelation(data).then((r) => { | |||
if (r.succeeded) { | |||
message.success('编辑成功'); | |||
} else { | |||
message.error(r.errors) | |||
} | |||
}); | |||
setIsModalOpen(false); | |||
setIsWeight(''); | |||
actionRef.current.reload(); | |||
}; | |||
const setrecipeList = async (id) => { | |||
var list = []; | |||
api.getStoreRelation(id).then((item) => { | |||
item.data.forEach(function (item) { | |||
list.push(item.recipeId); | |||
}) | |||
setTargetKeys(list); | |||
}); | |||
}; | |||
const handleChange = (newTargetKeys) => { | |||
setTargetKeys(newTargetKeys); | |||
}; | |||
const handleModeChange = (value) => { | |||
setIsWeight(value); | |||
getAllRecipeList(value); | |||
}; | |||
const columns = [ | |||
{ | |||
title: '主键', | |||
dataIndex: 'id', | |||
tip: 'key', | |||
hideInSearch: true, | |||
hideInTable: true | |||
}, | |||
{ | |||
title: '门店名称', | |||
dataIndex: 'name', | |||
ellipsis: true, | |||
}, | |||
{ | |||
title: '组织名称', | |||
dataIndex: 'orgName', | |||
ellipsis: true, | |||
hideInSearch: true, | |||
}, | |||
{ | |||
title: '负责人', | |||
dataIndex: 'header', | |||
ellipsis: true, | |||
hideInSearch: true, | |||
}, | |||
{ | |||
title: '手机号', | |||
dataIndex: 'phone', | |||
ellipsis: true, | |||
hideInSearch: true, | |||
}, | |||
{ | |||
title: '描述', | |||
dataIndex: 'description', | |||
ellipsis: true, | |||
hideInSearch: true, | |||
}, | |||
{ | |||
title: '操作', | |||
dataIndex: 'option', | |||
valueType: 'option', | |||
fixed: 'right', | |||
width: 350, | |||
render: (_, record) => [ | |||
<a | |||
onClick={() => { | |||
handleModalOpen(true); | |||
setStepFormValues(record); | |||
}} | |||
> | |||
更新 | |||
</a>, | |||
<a | |||
key="edit" | |||
onClick={() => { | |||
getHasDeviceRelation(record.id); | |||
getAllRecipeList(isWeight) | |||
setrecipeList(record.id); | |||
setStoreId(record.id); | |||
setIsModalOpen(true); | |||
}} | |||
> | |||
设置门店配方 | |||
</a>, | |||
<Popconfirm | |||
type="primary" | |||
key="primary" | |||
title="确认删除吗?" | |||
okText="是" | |||
cancelText="否" | |||
onConfirm={() => { | |||
api.deleteStore([record.id]).then((r) => { | |||
if (r.succeeded) { | |||
message.success('删除成功'); | |||
actionRef.current.reload(); | |||
} else { | |||
message.error(r.errors); | |||
} | |||
}); | |||
}} | |||
> | |||
<a href="#">删除</a> | |||
</Popconfirm>, | |||
], | |||
} | |||
] | |||
return ( | |||
<PageContainer | |||
header={{ | |||
title: '', | |||
breadcrumb: {}, | |||
}} | |||
> | |||
<ProTable | |||
headerTitle="门店列表" | |||
actionRef={actionRef} | |||
rowKey="id" | |||
pagination={{ defaultPageSize: 10 }} | |||
search={{ | |||
labelWidth: 120, | |||
}} | |||
toolBarRender={() => [ | |||
<Button | |||
type="primary" | |||
key="primary" | |||
onClick={() => { | |||
handleModalOpen(true); | |||
}} | |||
> | |||
<PlusOutlined /> 新建 | |||
</Button>, | |||
<BatchDeletion /> | |||
]} | |||
request={async (params) => { | |||
let storeData = []; | |||
var total = 0; | |||
await api.getStorePage(params).then((r) => { | |||
storeData = r.data.data; | |||
total = r.data.total; | |||
}); | |||
return { | |||
data: storeData, | |||
total: total, | |||
}; | |||
}} | |||
columns={columns} | |||
rowSelection={{ | |||
onChange: (_, selectedRows) => { | |||
setSelectedRows(selectedRows); | |||
}, | |||
}} | |||
/> | |||
<CreateForm | |||
treeData={treeData} | |||
onFinish={async (value) => { | |||
await api.updateStore(value).then(r => { | |||
if (r.data) { | |||
if (value.id == undefined) { | |||
message.success("添加成功") | |||
} | |||
else { | |||
message.success("修改成功") | |||
} | |||
} | |||
else { | |||
message.error(r.errors) | |||
} | |||
}) | |||
handleModalOpen(false); | |||
setStepFormValues({}); | |||
actionRef.current.reload(); | |||
}} | |||
onCancel={() => { | |||
handleModalOpen(false); | |||
setStepFormValues({}); | |||
}} | |||
modalOpen={createModalOpen} | |||
values={stepFormValues || {}} | |||
/> | |||
<Modal | |||
width={800} | |||
title="设置门店配方" | |||
open={isModalOpen} | |||
destroyOnClose | |||
footer={hasDeviceRelation ? <span style={{ color: '#FA541C' }}>已有设备使用,请取消该门店下所有设备的绑定配方!</span> : undefined} | |||
onOk={() => { editStoreRecipe() }} | |||
onCancel={() => { | |||
setIsModalOpen(false) | |||
setIsWeight('') | |||
}} | |||
> | |||
<Select | |||
defaultValue="全部" | |||
style={{ width: 120, marginBottom: 10 }} | |||
onChange={handleModeChange} | |||
> | |||
<Option value="">全部</Option> | |||
<Option value={false}>标准模式</Option> | |||
<Option value={true}>称重模式</Option> | |||
</Select> | |||
<Transfer | |||
className="tree-transfer" | |||
listStyle={{ | |||
width: 500, | |||
height: 500, | |||
}} | |||
dataSource={mockData} | |||
targetKeys={targetKeys} | |||
onChange={handleChange} | |||
showSearch | |||
pagination | |||
render={(item) => item.title} | |||
/> | |||
</Modal> | |||
</PageContainer> | |||
) | |||
} | |||
export default storeinfo; |
@@ -0,0 +1,51 @@ | |||
import { request } from 'umi'; | |||
import { getDataBaseUrl } from '@/global_data'; | |||
export default { | |||
getStorePage(params) { | |||
return request(getDataBaseUrl() + '/api/store/getStorePage', { | |||
method: 'Post', | |||
data: params, | |||
}); | |||
}, | |||
gettree(params) { | |||
return request(getDataBaseUrl() + '/api/organize/tree', { | |||
method: 'GET', | |||
data: { | |||
...params, | |||
}, | |||
}); | |||
}, | |||
updateStore(data) { | |||
return request(getDataBaseUrl() + '/api/store/updateStore', { | |||
method: 'Post', | |||
data: data, | |||
}); | |||
}, | |||
deleteStore(data) { | |||
return request(getDataBaseUrl() + '/api/store/deleteStore', { | |||
method: 'Post', | |||
data: data, | |||
}); | |||
}, | |||
getAllRecipeList(isWeight) { | |||
return request(getDataBaseUrl() + `/api/recipe/getAllRecipeList?isWeight=${isWeight}`, { | |||
method: 'Get', | |||
}); | |||
}, | |||
getHasDeviceRelation(id) { | |||
return request(getDataBaseUrl() + `/api/store/getHasDeviceRelation?storeId=${id}`, { | |||
method: 'Get', | |||
}); | |||
}, | |||
getStoreRelation(id) { | |||
return request(getDataBaseUrl() + `/api/store/getStoreRelation?storeId=${id}`, { | |||
method: 'Get', | |||
}); | |||
}, | |||
setStoreRelation(data) { | |||
return request(getDataBaseUrl() + '/api/store/setStoreRelation', { | |||
method: 'Post', | |||
data: data, | |||
}); | |||
}, | |||
} |
@@ -0,0 +1,96 @@ | |||
import { PageContainer } from "@ant-design/pro-layout"; | |||
import ProTable from "@ant-design/pro-table"; | |||
import api from './service'; | |||
import moment from 'moment'; | |||
const devicelog = () => { | |||
const columns = [ | |||
{ | |||
title: '主键', | |||
dataIndex: 'id', | |||
tip: 'key', | |||
hideInSearch: true, | |||
hideInTable: true | |||
}, | |||
{ | |||
title: '文件名称', | |||
dataIndex: 'fileName', | |||
ellipsis: true, | |||
}, | |||
{ | |||
title: '门店名称', | |||
dataIndex: 'storeName', | |||
ellipsis: true, | |||
}, | |||
{ | |||
title: '设备名称', | |||
dataIndex: 'deviceName', | |||
ellipsis: true, | |||
}, | |||
{ | |||
title: '创建时间', | |||
dataIndex: 'createAt', | |||
valueType: 'dateTimeRange', | |||
render: (_, record) => { | |||
return <span>{record.createAt}</span>; | |||
} | |||
}, | |||
{ | |||
title: '操作', | |||
dataIndex: 'option', | |||
valueType: 'option', | |||
fixed: 'right', | |||
width: 350, | |||
render: (_, record) => [ | |||
<a | |||
key="config" | |||
href={record.fileUrl} | |||
download | |||
> | |||
下载 | |||
</a> | |||
] | |||
} | |||
] | |||
return ( | |||
<PageContainer | |||
header={{ | |||
title: '', | |||
breadcrumb: {}, | |||
}} | |||
> | |||
<ProTable | |||
headerTitle="日志列表" | |||
rowKey="id" | |||
pagination={{ defaultPageSize: 10 }} | |||
search={{ | |||
labelWidth: 'auto', | |||
span: '1', | |||
collapseRender: false, | |||
defaultParams: { | |||
storeName: '99', | |||
// createAt: [moment().startOf('day'), moment().endOf('day')], | |||
}, | |||
}} | |||
request={async (params) => { | |||
let logData = []; | |||
var total = 0; | |||
params.startTime = params.createAt != undefined ? params.createAt[0] : null; | |||
params.endTime = params.createAt != undefined ? params.createAt[1] : null; | |||
await api.getDeviceLogPage(params).then((r) => { | |||
logData = r.data.data; | |||
total = r.data.total; | |||
}); | |||
return { | |||
data: logData, | |||
total: total | |||
}; | |||
}} | |||
columns={columns} | |||
/> | |||
</PageContainer> | |||
) | |||
} | |||
export default devicelog; |
@@ -0,0 +1,10 @@ | |||
import { request } from 'umi'; | |||
import { getDataBaseUrl } from '@/global_data'; | |||
export default { | |||
getDeviceLogPage(params) { | |||
return request(getDataBaseUrl() + '/api/store/getDeviceLogPage', { | |||
method: 'Post', | |||
data: params, | |||
}); | |||
}, | |||
} |
@@ -110,13 +110,13 @@ const Login = () => { | |||
<img alt="logo" className={styles.logo} src="/logo.png" /> | |||
</div> | |||
</Link> | |||
<div className={styles.desc}>黑菠萝智慧后厨解决方案</div> | |||
<div className={styles.desc}>配料系统</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div className={styles.main}> | |||
<div className={styles.title}>黑菠萝智慧后厨管理</div> | |||
<div className={styles.title}>配料系统</div> | |||
<ProForm | |||
initialValues={{ | |||
autoLogin: true, | |||