diff --git a/mock/propertyById.json b/mock/propertyById.json new file mode 100644 index 0000000..13f05d2 --- /dev/null +++ b/mock/propertyById.json @@ -0,0 +1,214 @@ +{ + "id": 89, + "createTime": "2023-08-21 11:43:46", + "updateTime": "2023-08-21 11:43:46", + "spuCode": "1-28X7LF", + "categoryId": 1272, + "prototypeName": "TEST男装", + "costPrice": 10.000000, + "maxSyntheticNumber": 100, + "createId": 1, + "isDelete": 2, + "categoryName": "男士短裤", + "prototypeImgs": [ + { + "id": 412, + "prototypeId": 89, + "imgId": 1991125, + "maskImgId": 1991130, + "imgName": "3.jpg", + "imgType": 2, + "imgWidth": 600.0, + "imgHeight": 600.0, + "imgUrl": "https://test.vogocm.com:9010/eshop/eshop_img/2023/8/21/20230821114346A056.jpg", + "locations": [ + { + "id": 394, + "prototypeImgId": 412, + "clipHeight": 139.2, + "clipWidth": 108.0, + "clipX": 230.4, + "clipY": 318.0, + "cropBoxJson": "{\"left\":317,\"top\":264.9999694824219,\"width\":90,\"height\":116.00003051757812}" + } + ] + }, + { + "id": 413, + "prototypeId": 89, + "imgId": 1991122, + "maskImgId": 1991131, + "imgName": "1.jpg", + "imgType": 2, + "imgWidth": 600.0, + "imgHeight": 600.0, + "imgUrl": "https://test.vogocm.com:9010/eshop/eshop_img/2023/8/21/20230821114346A053.jpg", + "locations": [ + { + "id": 395, + "prototypeImgId": 413, + "clipHeight": 145.2, + "clipWidth": 116.4, + "clipX": 224.4, + "clipY": 314.4001, + "cropBoxJson": "{\"left\":312,\"top\":262.00006103515625,\"width\":97,\"height\":121}" + } + ] + }, + { + "id": 414, + "prototypeId": 89, + "imgId": 1991127, + "imgName": "f60911abe38e82e9dd2aaa75f3292ed2.jpg", + "imgType": 2, + "imgWidth": 1000.0, + "imgHeight": 1000.0, + "imgUrl": "https://test.vogocm.com:9010/eshop/eshop_img/2023/8/21/20230821114346A058.jpg", + "locations": [ + { + "id": 396, + "prototypeImgId": 414, + "clipHeight": 234.0, + "clipWidth": 192.0, + "clipX": 190.0, + "clipY": 288.0, + "cropBoxJson": "{\"left\":220,\"top\":144,\"width\":96,\"height\":117}" + } + ] + }, + { + "id": 415, + "prototypeId": 89, + "imgId": 1991123, + "imgName": "d247c5ec0ef78f302b803c6bf00658a2.jpg", + "imgType": 2, + "imgWidth": 1000.0, + "imgHeight": 1000.0, + "imgUrl": "https://test.vogocm.com:9010/eshop/eshop_img/2023/8/21/20230821114346A054.jpg", + "locations": [ + { + "id": 397, + "prototypeImgId": 415, + "clipHeight": 279.9999, + "clipWidth": 226.0, + "clipX": 380.0, + "clipY": 404.0001, + "cropBoxJson": "{\"left\":315,\"top\":202.00006103515625,\"width\":113,\"height\":139.99993896484375}" + } + ] + }, + { + "id": 416, + "prototypeId": 89, + "imgId": 1991129, + "imgName": "b470dfa7876630bb2b6ba9ed294b58ca.jpg", + "imgType": 1, + "imgWidth": 1000.0, + "imgHeight": 1000.0, + "imgUrl": "https://test.vogocm.com:9010/eshop/eshop_img/2023/8/21/20230821114346A060.jpg", + "locations": [ + { + "id": 398, + "prototypeImgId": 416, + "clipHeight": 247.9999, + "clipWidth": 200.0, + "clipX": 414.0, + "clipY": 402.0001, + "cropBoxJson": "{\"left\":332,\"top\":201.00003051757812,\"width\":100,\"height\":123.99996948242188}" + } + ] + }, + { + "id": 417, + "prototypeId": 89, + "imgId": 1991124, + "imgName": "e870596429cb1e46065fe25a71b29070.jpg", + "imgType": 1, + "imgWidth": 1000.0, + "imgHeight": 1000.0, + "imgUrl": "https://test.vogocm.com:9010/eshop/eshop_img/2023/8/21/20230821114346A055.jpg", + "locations": [ + { + "id": 399, + "prototypeImgId": 417, + "clipHeight": 282.0, + "clipWidth": 216.0, + "clipX": 408.0, + "clipY": 394.0, + "cropBoxJson": "{\"left\":329,\"top\":197,\"width\":108,\"height\":141}" + } + ] + }, + { + "id": 418, + "prototypeId": 89, + "imgId": 1991128, + "imgName": "067b756a187026d1af97aa78b8d7d0ba.jpg", + "imgType": 1, + "imgWidth": 1000.0, + "imgHeight": 1000.0, + "imgUrl": "https://test.vogocm.com:9010/eshop/eshop_img/2023/8/21/20230821114346A059.jpg", + "locations": [ + { + "id": 400, + "prototypeImgId": 418, + "clipHeight": 300.0, + "clipWidth": 230.0001, + "clipX": 389.9999, + "clipY": 384.0, + "cropBoxJson": "{\"left\":319.99993896484375,\"top\":192,\"width\":115.00006103515625,\"height\":150}" + } + ] + }, + { + "id": 419, + "prototypeId": 89, + "imgId": 1991126, + "imgName": "e944022ccb44a7fb14483da12f1cf8eb.jpg", + "imgType": 1, + "imgWidth": 1000.0, + "imgHeight": 1000.0, + "imgUrl": "https://test.vogocm.com:9010/eshop/eshop_img/2023/8/21/20230821114346A057.jpg", + "locations": [ + { + "id": 401, + "prototypeImgId": 419, + "clipHeight": 299.9999, + "clipWidth": 206.0, + "clipX": 400.0, + "clipY": 392.0001, + "cropBoxJson": "{\"left\":325,\"top\":196.00006103515625,\"width\":103,\"height\":149.99993896484375}" + } + ] + } + ], + "materialClassifys": [ + { + "id": 20, + "createTime": "2023-04-10 17:41:00", + "updateTime": "2023-04-10 17:41:06", + "parentId": 2, + "classifyName": "海贼王", + "createId": 2, + "isDelete": 2 + }, + { + "id": 21, + "createTime": "2023-04-10 17:41:07", + "updateTime": "2023-04-10 17:41:13", + "parentId": 2, + "classifyName": "火影忍者", + "createId": 2, + "isDelete": 2 + }, + { + "id": 22, + "createTime": "2023-04-10 17:41:16", + "updateTime": "2023-04-10 17:41:22", + "parentId": 2, + "classifyName": "死神", + "createId": 2, + "isDelete": 2 + } + ] +} diff --git a/package.json b/package.json index 38039e4..4c0eb3e 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "vogocm-web", "private": true, - "version": "0.0.0", + "version": "0.0.1", "type": "module", "scripts": { "start": "vite", @@ -31,6 +31,7 @@ "nprogress": "^0.2.0", "rc-resize-observer": "^1.3.1", "react": "^18.2.0", + "react-advanced-cropper": "^0.19.3", "react-dom": "^18.2.0", "react-router-dom": "latest", "react-use": "^17.4.0", diff --git a/src/layout/header/index.tsx b/src/layout/header/index.tsx index 8524497..9878ff1 100644 --- a/src/layout/header/index.tsx +++ b/src/layout/header/index.tsx @@ -135,13 +135,13 @@ const Header = () => { >

- {currentUser?.userName} + {currentUser?.username}

- {currentUser?.phoneNumber} + {currentUser?.mobile}

- {currentUser?.emailAddress} + {currentUser?.email}


@@ -153,8 +153,8 @@ const Header = () => { }} >
- {currentUser?.avatarUrl ? ( - + {currentUser?.avatar ? ( + ) : ( } /> )} diff --git a/src/layout/index.tsx b/src/layout/index.tsx index 566261c..6a5a348 100644 --- a/src/layout/index.tsx +++ b/src/layout/index.tsx @@ -80,7 +80,7 @@ const BasicLayout: React.FC = () => { const formatedMenus = formatMenus(menus.filter(o => !o.parentId), menuGroup, routes); setMenus(formatedMenus); - console.log(components, 'components'); + console.log('components', components); replaceRoutes('*', [ ...routes.map(menu => ({ path: `/*${menu.path}`, @@ -100,9 +100,18 @@ const BasicLayout: React.FC = () => { path: '404', name: '404', }, + }, + { + path: `/*/custom/product/sample/editor`, + Component: lazy(components['/custom/product/sample/editor/index.tsx']), + id: `/*/custom/product/sample/editor`, + handle: { + parentPaths: ['/custom', '/custom/product', '/custom/product/sample'], + path: '/*/custom/product/sample/editor', + name: '蒙版编辑', + }, } ]); - setLoading(false); // replace一下当前路由,为了触发路由匹配 diff --git a/src/models/user.ts b/src/models/user.ts index fbfefd3..346d003 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -73,16 +73,15 @@ export interface Menu { export interface User { id: number; - userName: string; - nickName: string; - phoneNumber: string; + username: string; + nickname: string; + deptId:number; + postIds: number; + mobile: string; email: string; - createDate: string; - updateDate: string; - avatar?: any; - menus: Menu[]; - routes: any[]; - flatMenus: Menu[]; - avatarPath: string; - authList: string[]; + sex: number; + createTime: string; + loginDate: string; + avatar?: string; + status: number; } diff --git a/src/pages/custom/product/sample/components/mask-picture-editor.tsx b/src/pages/custom/product/sample/components/mask-picture-editor.tsx index a97f9fa..ddf9803 100644 --- a/src/pages/custom/product/sample/components/mask-picture-editor.tsx +++ b/src/pages/custom/product/sample/components/mask-picture-editor.tsx @@ -115,7 +115,7 @@ const MaskPictureEditor: React.FC = (props) => { url: item.maskImgUrl, }] : [] return ( -
+
; + +type LineComponent = FC; + +interface HandlerClassNames extends Partial> { + default?: string; + disabled?: string; + hover?: string; +} + +interface LineClassNames extends Partial> { + default?: string; + disabled?: string; + hover?: string; +} + +interface DesiredCropperRef { + getState: () => CropperState | null; + getTransitions: () => CropperTransitions; + getInteractions: () => CropperInteractions; + hasInteractions: () => boolean; + resizeCoordinates: (anchor: ResizeAnchor, directions: Partial, parameters: unknown) => void; + resizeCoordinatesEnd: () => void; + moveCoordinates: (directions: Partial) => void; + moveCoordinatesEnd: () => void; +} + +interface Props { + cropper: DesiredCropperRef; + coordinates?: Coordinates | ((state: CropperState | null) => Coordinates); + handlerComponent?: HandlerComponent; + handlers?: Partial>; + handlerClassNames?: HandlerClassNames; + handlerWrapperClassNames?: HandlerClassNames; + lines?: Partial>; + lineComponent?: LineComponent; + lineClassNames?: LineClassNames; + lineWrapperClassNames?: LineClassNames; + className?: string; + movingClassName?: string; + resizingClassName?: string; + gridClassName?: string; + previewClassName?: string; + boundingBoxClassName?: string; + overlayClassName?: string; + draggableAreaClassName?: string; + minAspectRatio?: number; + maxAspectRatio?: number; + aspectRatio?: RawAspectRatio; + movable?: boolean; + resizable?: boolean; + grid?: boolean; +} + +interface Methods { + aspectRatio: RawAspectRatio; +} + +export const ImageStencil = forwardRef( + ( + { + cropper, + coordinates, + aspectRatio, + minAspectRatio, + maxAspectRatio, + handlerComponent = SimpleHandler, + handlers = { + eastNorth: true, + north: true, + westNorth: true, + west: true, + westSouth: true, + south: true, + eastSouth: true, + east: true, + }, + handlerClassNames = {}, + handlerWrapperClassNames = {}, + lines = { + west: true, + north: true, + east: true, + south: true, + }, + lineComponent = SimpleLine, + lineClassNames = {}, + lineWrapperClassNames = {}, + resizable = true, + movable = true, + grid, + gridClassName, + className, + movingClassName, + resizingClassName, + previewClassName, + boundingBoxClassName, + overlayClassName, + draggableAreaClassName, + }: Props, + ref, + ) => { + const state = cropper.getState(); + const transitions = cropper.getTransitions(); + const interactions = cropper.getInteractions(); + + useImperativeHandle(ref, () => ({ + aspectRatio: createAspectRatio( + aspectRatio || { + minimum: minAspectRatio, + maximum: maxAspectRatio, + }, + ), + })); + + const onMove = (directions: MoveDirections) => { + if (cropper && movable) { + cropper.moveCoordinates(directions); + } + }; + + const onMoveEnd = () => { + if (cropper) { + cropper.moveCoordinatesEnd(); + } + }; + + const onResize = (anchor: ResizeAnchor, directions: MoveDirections, options: ResizeOptions) => { + if (cropper && resizable) { + cropper.resizeCoordinates(anchor, directions, options); + } + }; + + const onResizeEnd = () => { + if (cropper) { + cropper.resizeCoordinatesEnd(); + } + }; + + const { width, height, left, top } = coordinates + ? isFunction(coordinates) + ? coordinates(state) + : coordinates + : getStencilCoordinates(state); + + return ( + state && ( + + + + + + + + ) + ); + }, +); + +ImageStencil.displayName = 'ImageStencil'; diff --git a/src/pages/custom/product/sample/editor/index.tsx b/src/pages/custom/product/sample/editor/index.tsx new file mode 100644 index 0000000..a5498b4 --- /dev/null +++ b/src/pages/custom/product/sample/editor/index.tsx @@ -0,0 +1,29 @@ +import React, { useState } from 'react'; +import { CropperRef, Cropper } from 'react-advanced-cropper'; +import 'react-advanced-cropper/dist/style.css' +import { ImageStencil } from "./components/ImageStencil"; + +export default () => { + const [image] = useState( + 'https://test.vogocm.com:9010/eshop/eshop_img/2023/8/21/20230821114346A053.jpg', + ); + + const onChange = (cropper: CropperRef) => { + console.log(cropper.getCoordinates(), cropper.getCanvas()); + }; + + return ( + + ) +} diff --git a/src/pages/custom/product/sample/index.tsx b/src/pages/custom/product/sample/index.tsx index 32b7ce8..39f8d03 100644 --- a/src/pages/custom/product/sample/index.tsx +++ b/src/pages/custom/product/sample/index.tsx @@ -8,6 +8,7 @@ import SampleAttrEditor from './components/attr-editor' import MaskPictureEditor from './components/mask-picture-editor'; import type { SampleAttribute } from './components/attr-editor' import type { MaskPicture } from './components/mask-picture-editor'; +import { useNavigate } from 'react-router-dom'; interface DataType { id: number; @@ -79,7 +80,10 @@ const TablePage: React.FC = () => { // setEditData(record); setAttrEditorVisible(true); }}>属性设置 - 编辑 + { + navigate('/custom/product/sample/editor') + }}>编辑 删除 ), @@ -206,7 +210,7 @@ const TablePage: React.FC = () => { const [attrEditorVisible, setAttrEditorVisible] = useState(false); const [maskEditorVisible, setMaskEditorVisible] = useState(false); const [selectedRowKeys, setSelectedRowKeys] = useState([]); - + const navigate = useNavigate(); const cancelHandle = () => { setAttrEditorVisible(false); }; diff --git a/src/pages/login/index.tsx b/src/pages/login/index.tsx index 2a20401..10cad63 100644 --- a/src/pages/login/index.tsx +++ b/src/pages/login/index.tsx @@ -14,6 +14,7 @@ import './index.css' const Login = () => { const navigate = useNavigate(); const { runAsync: listMenus } = useRequest(userService.listMenus, { manual: true }); + const { runAsync: getProfile } = useRequest(userService.getProfile, { manual: true }); const { runAsync: login, loading } = useRequest(loginService.login, { manual: true }); const { runAsync: rerefshToken } = useRequest(loginService.rerefshToken, { manual: true }); const { setCurrentUser } = useUserStore(); @@ -28,9 +29,10 @@ const Login = () => { // data.data.avatarUrl = 'https://test.vogocm.com:9010/eshop/eshop_img/2023/5/24/43853633d16749bfb291f81bebb73451_20230524150631A001.jpg'; setRefreshToken(data.refreshToken); setToken(data.accessToken); - const [ _, { data: menus } ] = await listMenus() + const [ _, { data: menus } ] = await listMenus(); + const [err, {data: profile}] = await getProfile(); // const [ error, {data: tokenData}] = await rerefshToken(data.refreshToken) - debugger + setCurrentUser(profile) navigate('/'); }; diff --git a/src/request/index.ts b/src/request/index.ts index db8eee7..f902f64 100644 --- a/src/request/index.ts +++ b/src/request/index.ts @@ -13,8 +13,8 @@ import { ResponseDTO } from '@/models'; const { apiUrl = '' } = useGlobSetting(); - -const refreshTokenUrl = '/api/auth/refresh/token'; +const loginUrl = '/auth/login'; +const refreshTokenUrl = '/app-api/member/auth/refresh-token'; export type Response = Promise<[boolean, T, AxiosResponse]>; @@ -70,9 +70,10 @@ class Request { const {token} = useGlobalStore.getState(); - if (token) { + if (token && !axiosConfig.url?.endsWith(loginUrl)) { axiosConfig.headers.Authorization = `Bearer ${token}`; } + axiosConfig.headers['tenant-id'] = '1'; return Promise.resolve(axiosConfig); } @@ -99,6 +100,7 @@ class Request { this.requestingCount += 1; const {token} = useGlobalStore.getState(); config.headers.Authorization = `Bearer ${token}`; + config.headers['tenant-id'] = '1' resolve(config); } } diff --git a/src/request/service/user.ts b/src/request/service/user.ts index 6aca3ed..8b6bc7d 100644 --- a/src/request/service/user.ts +++ b/src/request/service/user.ts @@ -1,8 +1,12 @@ import request from '@/request'; -import { Menu } from '@/models'; +import { Menu, User } from '@/models'; export default { listMenus: () => { return request.get('/admin-api/system/auth/list-menus'); + }, + + getProfile: () => { + return request.get('/admin-api/system/user/profile/get') } }; diff --git a/src/router/config.tsx b/src/router/config.tsx index 71198eb..e7bf64b 100644 --- a/src/router/config.tsx +++ b/src/router/config.tsx @@ -8,24 +8,23 @@ export const components = Object.keys(modules).reduce Promi const formatPath = path.replace('../pages', ''); prev[formatPath] = async () => { try { - // 这里其实就是动态加载js,如果报错了说明js资源不存在 return await modules[path]() as any; } catch { - // 如果manifest已经存在了,就不用再请求了 - if (manifest) { - try { - // 有可能manifest是过期的,所以可能还会加载失败 - return await import('/' + manifest[`src/pages${formatPath}`]?.file); - } catch { - // 如果失败,重新获取一下manifest.json,拿到最新的路径 - manifest = await (await fetch('/manifest.json')).json() as any; - return await import('/' + manifest[`src/pages${formatPath}`]?.file); - } - } else { - // 如果manifest.json为空,请求manifest.json,并根据最新的路径加载对应js - manifest = await (await fetch('/manifest.json')).json() as any; - return await import('/' + manifest[`src/pages${formatPath}`]?.file); - } + // // 如果manifest已经存在了,就不用再请求了 + // if (manifest) { + // try { + // // 有可能manifest是过期的,所以可能还会加载失败 + // return await import('/' + manifest[`src/pages${formatPath}`]?.file); + // } catch { + // // 如果失败,重新获取一下manifest.json,拿到最新的路径 + // manifest = await (await fetch('/manifest.json')).json() as any; + // return await import('/' + manifest[`src/pages${formatPath}`]?.file); + // } + // } else { + // // 如果manifest.json为空,请求manifest.json,并根据最新的路径加载对应js + // manifest = await (await fetch('/manifest.json')).json() as any; + // return await import('/' + manifest[`src/pages${formatPath}`]?.file); + // } } } return prev; diff --git a/src/store/global/user.ts b/src/store/global/user.ts index f42a2c2..7aad7f6 100644 --- a/src/store/global/user.ts +++ b/src/store/global/user.ts @@ -1,9 +1,9 @@ -import { UserDTO } from '@/models'; +import { User } from '@/models'; import { create } from 'zustand'; import { devtools } from 'zustand/middleware'; interface State { - currentUser: UserDTO | null; + currentUser: User | null; } interface Action {