diff --git a/config/proxy.js b/config/proxy.js index c61822d..11e2fbd 100644 --- a/config/proxy.js +++ b/config/proxy.js @@ -9,7 +9,7 @@ export default { dev: { '/kitchen/': { - target: 'https://localhost:5001/', + target: 'http://kitchen.dev1.com/', changeOrigin: true, secure: false, //关闭证书验证 pathRewrite: { diff --git a/config/routes.js b/config/routes.js index 6dbd453..de3b438 100644 --- a/config/routes.js +++ b/config/routes.js @@ -98,6 +98,27 @@ export default [ }, ], }, + { + name: '小程序管理', + icon: 'BankFilled', + path: '/applet', + routes: [ + { + name: '页面管理', + icon: 'smile', + path: '/applet/pageManage', + component: './applet/pageManage', + access: 'k2', + }, + { + name: '素材管理', + icon: 'smile', + path: '/applet/material', + component: './applet/material', + access: 'k2', + }, + ] + }, { name: '物料管理', icon: 'DropboxSquareFilled', diff --git a/src/app.jsx b/src/app.jsx index f1440a1..0135254 100644 --- a/src/app.jsx +++ b/src/app.jsx @@ -224,6 +224,27 @@ export async function getInitialState() { }, ], }, + { + name: '小程序管理', + icon: 'BankFilled', + path: '/applet', + routes: [ + { + name: '页面管理', + icon: 'smile', + path: '/applet/pageManage', + component: './applet/pageManage', + access: 'k2', + }, + { + name: '素材管理', + icon: 'smile', + path: '/applet/material', + component: './applet/material', + access: 'k2', + }, + ] + }, { code: 'bom', name: '配方管理', diff --git a/src/pages/applet/material/index.jsx b/src/pages/applet/material/index.jsx new file mode 100644 index 0000000..8427cb3 --- /dev/null +++ b/src/pages/applet/material/index.jsx @@ -0,0 +1,482 @@ +import { PlusOutlined } from '@ant-design/icons'; +import ProTable from '@ant-design/pro-table'; +import { PageContainer } from '@ant-design/pro-layout'; +import { Button, Card, Image, Select, message, Modal, Input, Upload, Popconfirm } from 'antd'; +import React, { useRef, useState } from 'react'; +import appletAPI from "../service"; +import { useEffect } from 'react'; +import styles from "./index.less"; +import axios from 'axios'; + +const getBase64 = (file) => + new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = () => resolve(reader.result); + reader.onerror = (error) => reject(error); + }); + + + +const Material = () => { + const actionRef = useRef(); + const [selectedStore, setSelectedStore] = useState(''); + const [storeList, setStoreList] = useState([]); + const [isModalVisible, setIsModalVisible] = useState(false); + const [currentImage, setCurrentImage] = useState({ + id: '', + pageId: '', + materialName: '', + materialCode: '', + materialPath: [], + materialType: 0 + }); + + const [previewVisible, setPreviewVisible] = useState(false); + const [previewImage, setPreviewImage] = useState(''); + const [previewTitle, setPreviewTitle] = useState(''); + const [fileList, setFileList] = useState([]); + + const [miniPageList, setMiniPageList] = useState([]); + + const [currentPage, setCurrentPage] = useState(1); + const [pageSize, setPageSize] = useState(10); + const [total, setTotal] = useState(0); + + const handleCancel = () => setPreviewVisible(false); + const handlePreview = async (file) => { + if (!file.url && !file.preview) { + file.preview = await getBase64(file.originFileObj); + } + setPreviewImage(file.url || file.preview); + setPreviewVisible(true); + setPreviewTitle(file.name || file.url.substring(file.url.lastIndexOf('/') + 1)); + }; + + const handleChange = ({ fileList: newFileList }) => { + newFileList.forEach(item => { + item.status = 'done' + }); + setFileList(newFileList) + }; + + const columns = [ + { + title: '素材名称', + dataIndex: 'materialName', + ellipsis: true, + }, + { + title: '素材编码', + dataIndex: 'materialCode', + ellipsis: true, + }, + { + title: '素材图片', + dataIndex: 'materialPath', + render: (_, record) => ( + + + ) + }, + { + title: '操作', + valueType: 'option', + key: 'option', + render: (_, record) => [ + onEditMaterial(record)}> + 编辑 + , + onDeleteMaterial(record)} + okText="确定" + cancelText="取消" + > + 删除 + + ] + }, + ]; + + const uploadButton = ( +
+ +
+ Upload +
+
+ ); + + /** + * 获取店铺列表 + */ + const onFetchStoreList = async () => { + const response = await appletAPI.GetAllStore(); + if (response.isSuccess) { + setStoreList(response.data); + setSelectedStore(response.data[0].id); + } else { + message.error(response.msg || '获取店铺列表失败'); + } + } + + const uploadProp = { + name: 'file', + showUploadList: true, + multiple: false, + accept: '.png, .jpg, .jpeg, .gif', + // 这里需要指定文件上传的content-type + headers: { + 'Content-Type': 'application/octet-stream', + }, + customRequest({ + action, + file, + headers, + onError, + onProgress, + withCredentials, + }) { + //覆盖action 上传之前获取上传地址 + var index = file.name.lastIndexOf("."); + var ext = file.name.substr(index + 1); + let fileData = null; + appletAPI.GetCosRequestURL({ directory: "applet", fileExtension: ext, method: "PUT" }).then((r) => { + action = r.allUrl; + const reader = new FileReader(); + reader.readAsArrayBuffer(file); + reader.onload = (e) => { + fileData = e.target.result; + axios.put(action, fileData, { + withCredentials, + headers, + onUploadProgress: ({ total, loaded }) => { + onProgress({ percent: Math.round(loaded / total * 100).toFixed(2) }, file); + }, + }).then(response => { + if (response.status == 200 || response.statusText == 'OK') { + const tempUploadImage = JSON.parse(JSON.stringify(currentImage)); + tempUploadImage.materialPath.push(r.seeUrl); + setCurrentImage(tempUploadImage); + message.success('上传成功!'); + } + }).catch(onError); + }; + }); + return { + abort() { + console.log('upload progress is aborted.'); + }, + }; + }, + }; + + /** + * 添加、更新页面素材 + */ + const onAddPageMaterial = async () => { + console.log('currentImage>>>>', currentImage, !currentImage.pageId); + if (!currentImage.pageId) { + message.info('请选择所属页面'); + return; + } else if (!currentImage.materialName) { + message.info('请填写素材名称'); + return; + } else if (!currentImage.materialCode) { + message.info('请填写素材编码'); + return; + } else if (currentImage.materialPath.length === 0) { + message.info('请选择至少上传一张素材图片'); + return; + } + const jsonData = { + pageId: currentImage.pageId, + materialName: currentImage.materialName, + materialCode: currentImage.materialCode, + materialPath: JSON.stringify(currentImage.materialPath), + materialType: currentImage.materialType + } + if (!currentImage.id) { + jsonData.id = currentImage.id; + const response = await appletAPI.UpdateMiniMaterial(jsonData); + if (response.statusCode === 200) { + message.success('更新成功'); + setIsModalVisible(false); + actionRef.current.reload(); + } else { + message.error('更新失败') + } + } else { + const response = await appletAPI.AddMinimaterial(jsonData); + if (response.statusCode === 200) { + message.success('添加成功'); + setIsModalVisible(false); + actionRef.current.reload(); + } else { + message.error('添加失败') + } + } + } + + /** + * 编辑素材 + * @param {*} record + */ + const onEditMaterial = (record) => { + const materialPath = JSON.parse(record.materialPath); + const material = { + id: record.id, + pageId: record.pageId, + materialName: record.materialName, + materialCode: record.materialCode, + materialPath: materialPath + } + if (materialPath.length > 1) { + material.materialType = 1; + } else { + material.materialType = 0; + } + const fileList = []; + materialPath.forEach((item, index) => { + fileList.push({ + uid: index, + name: item.split('/applet/')[1] || "图片.jpg", + status: 'done', + url: item, + }); + }); + setFileList(fileList); + setCurrentImage(material); + setIsModalVisible(true); + } + + /** + * 删除素材 + * @param {*} record + */ + const onDeleteMaterial = async (record) => { + const response = await appletAPI.DeleteMiniMaterial(record.id); + if (response.statusCode === 200) { + actionRef.current.reload(); + message.success('删除成功'); + } else { + message.error(response.errors || '删除失败'); + } + } + + /** + * 获取小程序页面 + */ + const onFetchMiniPageList = async () => { + const response = await appletAPI.MiniPageList({ + current: 1, + pageSize: 999, + storeId: selectedStore + }); + if (response.statusCode === 200) { + setMiniPageList(response.data.items); + } else { + message.error(response.errors || '获取页面列表失败') + } + } + + const onBeforeCreate = () => { + setFileList([]); + setCurrentImage({ + pageId: '', + materialName: '', + materialCode: '', + materialPath: [], + materialType: 0 + }); + } + + useEffect(() => { + onFetchStoreList(); + }, []); + + useEffect(() => { + if (!selectedStore) return; + onFetchMiniPageList(); + actionRef.current.reload(); + }, [selectedStore]); + + return + +
+
+ 当前门店: +
+ +
+
+ { + if (!selectedStore) return; + const jsonData = { + "current": currentPage, + "pageSize": pageSize, + "storeId": selectedStore + } + const response = await appletAPI.MinimaterialListByStore(jsonData); + const pageList = []; + response.data.forEach(item => { + pageList.push(...item.list); + }); + return { + data: pageList, + success: true, + total: 10, + } + }} + columnsState={{ + persistenceKey: 'pro-table-singe-demos', + persistenceType: 'localStorage', + onChange(value) { + console.log('value: ', value); + }, + }} + rowKey="id" + options={{ + setting: { + listsHeight: 400, + }, + }} + pagination={{ + pageSize: 5, + onChange: (page) => console.log(page), + }} + dateFormatter="string" + headerTitle="图片管理" + toolBarRender={() => [ + + ]} + /> + setIsModalVisible(false)}> +
+
+
+ 素材名称: +
+
+ { + const tempImg = JSON.parse(JSON.stringify(currentImage)); + tempImg.materialName = value.target.value; + setCurrentImage(tempImg); + }}> +
+
+
+
+ 素材编码: +
+
+ { + const tempImg = JSON.parse(JSON.stringify(currentImage)); + tempImg.materialCode = value.target.value; + setCurrentImage(tempImg); + }}> +
+
+
+
+ 所属页面: +
+
+ +
+
+
+
+ 数量: +
+
+ +
+
+ { + const findIndex = fileList.findIndex(item => item.uid === remove.uid); + if (findIndex > -1) { + const tempUpload = JSON.parse(JSON.stringify(currentImage)); + tempUpload.materialPath.splice(findIndex, 1); + setCurrentImage(tempUpload); + } + }} + {...uploadProp} + > + { + (() => { + if (currentImage.materialType === 0) { + if (fileList.length >= 1) { + return null; + } else { + return uploadButton + } + } else { + return <>{fileList.length >= 9 ? null : uploadButton} + } + })() + } + +
+
+ + example + +
+} + +export default Material; \ No newline at end of file diff --git a/src/pages/applet/material/index.less b/src/pages/applet/material/index.less new file mode 100644 index 0000000..341b9f6 --- /dev/null +++ b/src/pages/applet/material/index.less @@ -0,0 +1,12 @@ +.table_search_item { + display: flex; + align-items: center; +} + +.edit_image_item { + margin-bottom: 10px; +} + +.edit_image_prev { + margin-bottom: 5px; +} \ No newline at end of file diff --git a/src/pages/applet/pageManage/index.jsx b/src/pages/applet/pageManage/index.jsx new file mode 100644 index 0000000..1f34ee5 --- /dev/null +++ b/src/pages/applet/pageManage/index.jsx @@ -0,0 +1,242 @@ +import ProTable from '@ant-design/pro-table'; +import { PageContainer } from '@ant-design/pro-layout'; +import { PlusOutlined } from '@ant-design/icons'; +import { Button, Modal, Form, Input, Select, Card, message, Popconfirm } from 'antd'; +import React, { useRef, useState, useEffect } from 'react'; +import appletAPI from "../service"; +import styles from "./index.less"; + +const pageManage = () => { + const actionRef = useRef(); + const [isModalVisible, setIsModalVisible] = useState(false); + const [pageForm] = Form.useForm(); + const [storeList, setStoreList] = useState([]); + const [currentPage, setCurrentPage] = useState(1); + const [pageSize, setPageSize] = useState(10); + const [total, setTotal] = useState(0); + const [selectedStore, setSelectedStore] = useState(''); + + const columns = [ + { + title: '页面名称', + dataIndex: 'pageName', + ellipsis: true, + }, + { + title: '页面路径', + dataIndex: 'pageRoute', + ellipsis: true, + }, + { + title: '所属门店', + dataIndex: 'storeId', + ellipsis: true, + }, + { + title: '操作', + valueType: 'option', + key: 'option', + render: (_, record) => [ + { + pageForm.setFieldsValue(record); + setIsModalVisible(true); + }}> + 编辑 + , + onDeletePage(record)} + okText="确定" + cancelText="取消" + > + 删除 + + ], + } + ]; + + const onBeforeCreate = () => { + setIsModalVisible(true); + pageForm.resetFields(); + } + + /** + * 添加/修改页面信息 + */ + const onFinishPage = async (values) => { + if (values.id) { + const response = await appletAPI.MiniPageUpdate(values); + if (response.statusCode === 200) { + message.success('修改成功'); + setIsModalVisible(false); + actionRef.current.reload(); + } else { + message.error(response.errors); + } + } else { + const response = await appletAPI.MiniPageAdd(values); + if (response.statusCode === 200) { + message.success('添加成功'); + setIsModalVisible(false); + actionRef.current.reload(); + } else { + message.error(response.errors); + } + } + } + + /** + * 删除页面 + * @param {*} record + */ + const onDeletePage = async (record) => { + const response = await appletAPI.MiniPageDelete(record.id); + if (response.statusCode === 200) { + message.success('删除成功'); + actionRef.current.reload(); + } else { + message.error(response.errors); + } + } + + /** + * 获取店铺列表 + */ + const onFetchStoreList = async () => { + const response = await appletAPI.GetAllStore(); + if (response.isSuccess) { + setStoreList(response.data); + setSelectedStore(response.data[0].id); + } else { + message.error(response.msg || '获取店铺列表失败'); + } + } + + useEffect(() => { + onFetchStoreList(); + }, []); + + useEffect(() => { + actionRef.current.reload(); + }, [selectedStore]); + + return + +
+
+ 当前门店: +
+ +
+
+ { + if (!selectedStore) return; + const jsonData = { + "current": currentPage, + "pageSize": pageSize, + "storeId": selectedStore + } + const response = await appletAPI.MiniPageList(jsonData); + return { + data: response.data.items, + success: true, + total: response.data.totalCount, + } + }} + rowKey="id" + search={false} + pagination={{ + pageSize: 5, + onChange: (page) => console.log(page), + }} + dateFormatter="string" + headerTitle="页面管理" + toolBarRender={() => [ + + ]} + /> + setIsModalVisible(false)} onCancel={() => setIsModalVisible(false)}> +
+ + + + + + + + + + + + + + + + +
+
+
+} + +export default pageManage; \ No newline at end of file diff --git a/src/pages/applet/pageManage/index.less b/src/pages/applet/pageManage/index.less new file mode 100644 index 0000000..341b9f6 --- /dev/null +++ b/src/pages/applet/pageManage/index.less @@ -0,0 +1,12 @@ +.table_search_item { + display: flex; + align-items: center; +} + +.edit_image_item { + margin-bottom: 10px; +} + +.edit_image_prev { + margin-bottom: 5px; +} \ No newline at end of file diff --git a/src/pages/applet/service.js b/src/pages/applet/service.js new file mode 100644 index 0000000..44977c9 --- /dev/null +++ b/src/pages/applet/service.js @@ -0,0 +1,115 @@ +import { request } from 'umi'; + +export default { + GetAllStore() { + return request('/kitchen/api/StoreHelper/GetAllStore', { + method: 'GET' + }); + }, + + GetCosRequestURL(data) { + return request(`/kitchen/api/systemconfig/GetCosRequestSignURL`, { + method: 'POST', + data: data, + }); + }, + + /** + * 添加素材 + * @param {*} params + * @returns + */ + AddMinimaterial(params) { + return request(`/kitchen/api/minimaterial/add`, { + method: 'POST', + data: params, + }); + }, + + /** + * 更新素材 + * @param {*} params + */ + UpdateMiniMaterial(params) { + return request(`/kitchen/api/minimaterial/update`, { + method: 'POST', + data: params, + }); + }, + + /** + * 根据店铺id查询素材 + */ + MinimaterialListByStore(params) { + return request(`/kitchen/api/minimaterial/store`, { + method: 'POST', + data: params, + }); + }, + + /** + * 删除素材 + */ + DeleteMiniMaterial(id) { + return request(`/kitchen/api/minimaterial/del`, { + method: 'POST', + data: { + id + }, + }); + }, + + /** + * 添加页面 + * @param {*} params + * @returns + */ + MiniPageAdd(params) { + return request('/kitchen/api/minipage/add', { + method: 'POST', + data: { + ...params + } + }); + }, + + /** + * 删除 + * @param {*} id + * @returns + */ + MiniPageDelete(id) { + return request('/kitchen/api/minipage/del', { + method: 'POST', + data: { + id + } + }); + }, + + /** + * 更新页面 + * @param {*} params + */ + MiniPageUpdate(params) { + return request('/kitchen/api/minipage/update', { + method: 'POST', + data: { + ...params + } + }); + }, + + /** + * 分页查询 + */ + MiniPageList(params) { + return request('/kitchen/api/minipage/page', { + method: 'POST', + data: { + ...params + } + }); + } + +} \ No newline at end of file