diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..7e3649a --- /dev/null +++ b/.editorconfig @@ -0,0 +1,16 @@ +# http://editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false + +[Makefile] +indent_style = tab diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..dafff25 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,9 @@ +/lambda/ +/scripts +/config +.history +public +dist +.umi +mock +src \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..b882c20 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,8 @@ +module.exports = { + extends: [require.resolve('@umijs/fabric/dist/eslint')], + globals: { + ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: true, + page: true, + REACT_APP_ENV: true, + }, +}; diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..d17efb4 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,23 @@ +**/*.svg +package.json +.umi +.umi-production +/dist +.dockerignore +.DS_Store +.eslintignore +*.png +*.toml +docker +.editorconfig +Dockerfile* +.gitignore +.prettierignore +LICENSE +.eslintcache +*.lock +yarn-error.log +.history +CNAME +/build +/public \ No newline at end of file diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000..7b597d7 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,5 @@ +const fabric = require('@umijs/fabric'); + +module.exports = { + ...fabric.prettier, +}; diff --git a/.stylelintrc.js b/.stylelintrc.js new file mode 100644 index 0000000..c203078 --- /dev/null +++ b/.stylelintrc.js @@ -0,0 +1,5 @@ +const fabric = require('@umijs/fabric'); + +module.exports = { + ...fabric.stylelint, +}; diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..066f96b --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,142 @@ + +def getHost(){ + def remote = [:] + remote.name = 'eip' + remote.host = '10.6.1.50' + remote.user = 'root' + remote.port = 22 + remote.password = '120962839' + remote.allowAnyHosts = true + return remote +} + +pipeline{ + agent any + parameters { + choice( + description: 'EIP环境', + name: 'environment', + choices: ['dev1'] + ) + + choice( + description: '执行操作(发布|回滚)', + name: 'operation', + choices: ['develop', 'rollback'] + ) + + choice( + description: '是否下载包', + name: 'isDownloadPackage', + choices: ['是','否'] + ) + + string( + name: 'tag', + defaultValue: '', + description: '版本tag' + ) + + } + + stages + { + + stage('Prepare') { + steps { + script{ + echo "1.Prepare Stage" + echo "当前环境${params.environment}" + if(params.operation=='develop') + { + checkout scm + script { + build_tag = sh(returnStdout: true, script: 'git rev-parse --short HEAD').trim() + if (env.BRANCH_NAME != 'master') { + build_tag = "${env.BRANCH_NAME}-${build_tag}" + } + } + } + else{ + build_tag="${params.tag}" + } + } + } + } + stage('Test') { + steps { + script{ + echo "2.Test Stage" + } + } + + } + stage('Build') { + steps { + script{ + echo "3.Build Docker Image Stage" + if(params.operation=='develop') + { + nodejs("nodejs") { + + } + if(params.isDownloadPackage=='是') + { + sh "npm install --unsafe-perm=true --allow-root" + sh "rm -rf ./dist/*" + sh "npm run build" + } + sh "docker build -t 10.2.1.24:10242/bpa/kitchenweb:${build_tag} ." + } + } + } + + } + + + + + + stage('Push') { + steps { + script{ + echo "4.Push Docker Image Stage" + withCredentials([usernamePassword(credentialsId: 'harbor', passwordVariable: 'harborPassword', usernameVariable: 'harborUser')]) { + sh "docker login -u ${harborUser} -p ${harborPassword} 10.2.1.24:10242" + if(params.operation=='develop') + { + sh "docker push 10.2.1.24:10242/bpa/kitchenweb:${build_tag}" + } + } + } + } + + + + + } + + + stage('Deploy') { + + steps { + script{ + echo "5. Deploy Stage" + // server = getHost() + // sshCommand remote: server, command: """ + // /root/eip/web/shell/linux-eipweb.install.sh eipweb ${build_tag} 80 + // """ + + sh "sed -i 's//${build_tag}/' k8s_kitchenweb.yaml" + sh "sed -i 's//${env.BRANCH_NAME}/' k8s_kitchenweb.yaml" + sh "sed -i 's//${params.environment}/' k8s_kitchenweb.yaml" + sh "kubectl apply -f k8s_kitchenweb.yaml --record" + } + + + + } + } + } + +} diff --git a/config/config.dev.js b/config/config.dev.js new file mode 100644 index 0000000..8e33701 --- /dev/null +++ b/config/config.dev.js @@ -0,0 +1,14 @@ +// https://umijs.org/config/ +import { defineConfig } from 'umi'; +export default defineConfig({ + plugins: [ + // https://github.com/zthxxx/react-dev-inspector + 'react-dev-inspector/plugins/umi/react-inspector', + ], + // https://github.com/zthxxx/react-dev-inspector#inspector-loader-props + inspectorConfig: { + exclude: [], + babelPlugins: [], + babelOptions: {}, + }, +}); diff --git a/config/config.js b/config/config.js new file mode 100644 index 0000000..6db2c1f --- /dev/null +++ b/config/config.js @@ -0,0 +1,74 @@ +// https://umijs.org/config/ +import { defineConfig } from 'umi'; +import { join } from 'path'; +import defaultSettings from './defaultSettings'; +import proxy from './proxy'; +import routes from './routes'; +const { REACT_APP_ENV } = process.env; +export default defineConfig({ + hash: true, + antd: {}, + dva: { + hmr: true, + }, + define: { + 'process.env.UMI_ENV': process.env.UMI_ENV || 'dev', + }, + layout: { + // https://umijs.org/zh-CN/plugins/plugin-layout + locale: false, + siderWidth: 208, + ...defaultSettings, + }, + // https://umijs.org/zh-CN/plugins/plugin-locale + locale: { + // default zh-CN + default: 'zh-CN', + antd: true, + // default true, when it is true, will use `navigator.language` overwrite default + baseNavigator: true, + }, + dynamicImport: { + loading: '@ant-design/pro-layout/es/PageLoading', + }, + targets: { + ie: 11, + }, + // umi routes: https://umijs.org/docs/routing + routes, + // Theme for antd: https://ant.design/docs/react/customize-theme-cn + theme: { + 'primary-color': defaultSettings.primaryColor, + }, + // esbuild is father build tools + // https://umijs.org/plugins/plugin-esbuild + esbuild: {}, + title: false, + ignoreMomentLocale: true, + proxy: proxy[REACT_APP_ENV || 'dev'], + manifest: { + basePath: '/', + }, + // Fast Refresh 热更新 + fastRefresh: {}, + openAPI: [ + { + requestLibPath: "import { request } from 'umi'", + // 或者使用在线的版本 + // schemaPath: "https://gw.alipayobjects.com/os/antfincdn/M%24jrzTTYJN/oneapi.json" + schemaPath: join(__dirname, 'oneapi.json'), + mock: false, + }, + { + requestLibPath: "import { request } from 'umi'", + schemaPath: 'https://gw.alipayobjects.com/os/antfincdn/CA1dOm%2631B/openapi.json', + projectName: 'swagger', + }, + ], + nodeModulesTransform: { + type: 'none', + }, + mfsu: {}, + webpack5: {}, + exportStatic: {}, +}); diff --git a/config/defaultSettings.js b/config/defaultSettings.js new file mode 100644 index 0000000..fc6f382 --- /dev/null +++ b/config/defaultSettings.js @@ -0,0 +1,16 @@ +const Settings = { + navTheme: 'dark', + // 拂晓蓝 + primaryColor: '#FA541C', //'#1890ff', + layout: 'side', + contentWidth: 'Fluid', + fixedHeader: false, + fixSiderbar: true, + colorWeak: false, + title: '黑菠萝智慧餐厨', + pwa: false, + logo: '/logo.svg', + iconfontUrl: '', +}; + +export default Settings; diff --git a/config/oneapi.json b/config/oneapi.json new file mode 100644 index 0000000..78efb57 --- /dev/null +++ b/config/oneapi.json @@ -0,0 +1,619 @@ +{ + "openapi": "3.0.1", + "info": { + "title": "Ant Design Pro", + "version": "1.0.0" + }, + "servers": [ + { + "url": "http://localhost:44324/" + }, + { + "url": "https://localhost:44324/" + } + ], + "paths": { + "/kitchen/api/currentUser": { + "get": { + "tags": [ + "api" + ], + "description": "获取当前的用户", + "operationId": "currentUser", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CurrentUser" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "x-swagger-router-controller": "api" + }, + "/kitchen/api/login/captcha": { + "post": { + "description": "发送验证码", + "operationId": "getFakeCaptcha", + "tags": [ + "login" + ], + "parameters": [ + { + "name": "phone", + "in": "query", + "description": "手机号", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FakeCaptcha" + } + } + } + } + } + } + }, + "/kitchen/api/login/outLogin": { + "post": { + "description": "登录接口", + "operationId": "outLogin", + "tags": [ + "login" + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "x-swagger-router-controller": "api" + }, + "/kitchen/api/login/account": { + "post": { + "tags": [ + "login" + ], + "description": "登录接口", + "operationId": "login", + "requestBody": { + "description": "登录系统", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginParams" + } + } + }, + "required": true + }, + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LoginResult" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + }, + "x-codegen-request-body-name": "body" + }, + "x-swagger-router-controller": "api" + }, + "/kitchen/api/notices": { + "summary": "getNotices", + "description": "NoticeIconItem", + "get": { + "tags": [ + "api" + ], + "operationId": "getNotices", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NoticeIconList" + } + } + } + } + } + } + }, + "/kitchen/api/rule": { + "get": { + "tags": [ + "rule" + ], + "description": "获取规则列表", + "operationId": "rule", + "parameters": [ + { + "name": "current", + "in": "query", + "description": "当前的页码", + "schema": { + "type": "number" + } + }, + { + "name": "pageSize", + "in": "query", + "description": "页面的容量", + "schema": { + "type": "number" + } + } + ], + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleList" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "post": { + "tags": [ + "rule" + ], + "description": "新建规则", + "operationId": "addRule", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleListItem" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "put": { + "tags": [ + "rule" + ], + "description": "新建规则", + "operationId": "updateRule", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleListItem" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "delete": { + "tags": [ + "rule" + ], + "description": "删除规则", + "operationId": "removeRule", + "responses": { + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "object" + } + } + } + }, + "401": { + "description": "Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + }, + "x-swagger-router-controller": "api" + }, + "/swagger": { + "x-swagger-pipe": "swagger_raw" + } + }, + "components": { + "schemas": { + "CurrentUser": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "avatar": { + "type": "string" + }, + "userid": { + "type": "string" + }, + "email": { + "type": "string" + }, + "signature": { + "type": "string" + }, + "title": { + "type": "string" + }, + "group": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "type": "object", + "properties": { + "key": { + "type": "string" + }, + "label": { + "type": "string" + } + } + } + }, + "notifyCount": { + "type": "integer", + "format": "int32" + }, + "unreadCount": { + "type": "integer", + "format": "int32" + }, + "country": { + "type": "string" + }, + "access": { + "type": "string" + }, + "geographic": { + "type": "object", + "properties": { + "province": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "key": { + "type": "string" + } + } + }, + "city": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "key": { + "type": "string" + } + } + } + } + }, + "address": { + "type": "string" + }, + "phone": { + "type": "string" + } + } + }, + "LoginResult": { + "type": "object", + "properties": { + "status": { + "type": "string" + }, + "type": { + "type": "string" + }, + "currentAuthority": { + "type": "string" + } + } + }, + "PageParams": { + "type": "object", + "properties": { + "current": { + "type": "number" + }, + "pageSize": { + "type": "number" + } + } + }, + "RuleListItem": { + "type": "object", + "properties": { + "key": { + "type": "integer", + "format": "int32" + }, + "disabled": { + "type": "boolean" + }, + "href": { + "type": "string" + }, + "avatar": { + "type": "string" + }, + "name": { + "type": "string" + }, + "owner": { + "type": "string" + }, + "desc": { + "type": "string" + }, + "callNo": { + "type": "integer", + "format": "int32" + }, + "status": { + "type": "integer", + "format": "int32" + }, + "updatedAt": { + "type": "string", + "format": "datetime" + }, + "createdAt": { + "type": "string", + "format": "datetime" + }, + "progress": { + "type": "integer", + "format": "int32" + } + } + }, + "RuleList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RuleListItem" + } + }, + "total": { + "type": "integer", + "description": "列表的内容总数", + "format": "int32" + }, + "success": { + "type": "boolean" + } + } + }, + "FakeCaptcha": { + "type": "object", + "properties": { + "code": { + "type": "integer", + "format": "int32" + }, + "status": { + "type": "string" + } + } + }, + "LoginParams": { + "type": "object", + "properties": { + "username": { + "type": "string" + }, + "password": { + "type": "string" + }, + "autoLogin": { + "type": "boolean" + }, + "type": { + "type": "string" + } + } + }, + "ErrorResponse": { + "required": [ + "errorCode" + ], + "type": "object", + "properties": { + "errorCode": { + "type": "string", + "description": "业务约定的错误码" + }, + "errorMessage": { + "type": "string", + "description": "业务上的错误信息" + }, + "success": { + "type": "boolean", + "description": "业务上的请求是否成功" + } + } + }, + "NoticeIconList": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/NoticeIconItem" + } + }, + "total": { + "type": "integer", + "description": "列表的内容总数", + "format": "int32" + }, + "success": { + "type": "boolean" + } + } + }, + "NoticeIconItemType": { + "title": "NoticeIconItemType", + "description": "已读未读列表的枚举", + "type": "string", + "properties": {}, + "enum": [ + "notification", + "message", + "event" + ] + }, + "NoticeIconItem": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "extra": { + "type": "string", + "format": "any" + }, + "key": { + "type": "string" + }, + "read": { + "type": "boolean" + }, + "avatar": { + "type": "string" + }, + "title": { + "type": "string" + }, + "status": { + "type": "string" + }, + "datetime": { + "type": "string", + "format": "date" + }, + "description": { + "type": "string" + }, + "type": { + "extensions": { + "x-is-enum": true + }, + "$ref": "#/components/schemas/NoticeIconItemType" + } + } + } + } + } +} diff --git a/config/proxy.js b/config/proxy.js new file mode 100644 index 0000000..39b99d2 --- /dev/null +++ b/config/proxy.js @@ -0,0 +1,89 @@ +/** + * 在生产环境 代理是无法生效的,所以这里没有生产环境的配置 + * ------------------------------- + * The agent cannot take effect in the production environment + * so there is no configuration of the production environment + * For details, please see + * https://pro.ant.design/docs/deploy + */ + export default { + dev: { + '/saasbase/': { + target: 'http://192.168.1.19:5006', + changeOrigin: true, + secure: false, //关闭证书验证 + pathRewrite: { + '/saasbase/': '', + }, + }, + // Nginx发布的时候需要配置 + '/cos/':{ + target: 'https://hbl-test-1305371387.cos.ap-chengdu.myqcloud.com', + changeOrigin: true, + secure: false, //关闭证书验证 + pathRewrite: { + '/cos/': '/', + }, + } + }, + test: { + '/api/': { + target: 'http://localhost:5006', + changeOrigin: true, + secure: false, + pathRewrite: { + '^': '', + }, + }, + }, + pre: { + '/api/': { + target: 'http://localhost:5006', + changeOrigin: true, + secure: false, + pathRewrite: { + '^': '', + }, + }, + }, +}; +// /** +// * 在生产环境 代理是无法生效的,所以这里没有生产环境的配置 +// * ------------------------------- +// * The agent cannot take effect in the production environment +// * so there is no configuration of the production environment +// * For details, please see +// * https://pro.ant.design/docs/deploy +// */ +// export default { +// dev: { +// '/api/': { +// target: 'http://114.117.161.250:7002', +// changeOrigin: true, +// secure: false, //关闭证书验证 +// pathRewrite: { +// '^': '', +// }, +// }, +// }, +// test: { +// '/api/': { +// target: 'http://114.117.161.250:7002', +// changeOrigin: true, +// secure: false, +// pathRewrite: { +// '^': '', +// }, +// }, +// }, +// pre: { +// '/api/': { +// target: 'http://114.117.161.250:7002', +// changeOrigin: true, +// secure: false, +// pathRewrite: { +// '^': '', +// }, +// }, +// }, +// }; diff --git a/config/routes.js b/config/routes.js new file mode 100644 index 0000000..8754d40 --- /dev/null +++ b/config/routes.js @@ -0,0 +1,217 @@ +/** + * SYS 系统设置 + * admin 系统用户 + * erp 供应链管理 + * basic 基础信息管理 + * bill 单据管理 + * crm crm会员管理 + * franchisee 加盟商 + * srd 店铺管理 + **/ +export default [ + { + path: '/user', + layout: false, + routes: [ + { + name: '系统登录', + path: '/user/login', + component: './user/login', + access: 'k1', + }, + ], + }, + { + name: '系统管理', + icon: 'SettingOutlined', + path: '/sys', + routes: [ + { + name: '系统菜单', + icon: 'smile', + path: '/sys/menus', + component: './sys/menus', + access: 'k6', + }, + // { + // name: '字典信息', + // icon: 'smile', + // path: '/sys/dictionary/dictdata', + // component: './sys/dictionary/dictdata', + // access: 'k6', + // }, + { + name: '字典类型', + icon: 'smile', + path: '/sys/dictionary/dicttype', + component: './sys/dictionary/dicttype', + access: 'k6', + }, + // { + // name: '操作日志', + // icon: 'smile', + // path: '/sys/log', + // component: './sys/log', + // access: 'k3', + // }, + // { + // name: '错误日志', + // icon: 'smile', + // path: '/sys/log', + // component: './sys/log', + // access: 'k3', + // }, + + ], + }, + { + name: '加盟商管理', + icon: 'SettingOutlined', + path: '/company', + routes: [ + { + name: '账号管理', + icon: 'smile', + path: '/company/account', + component: './company/account', + access: 'k2', + }, + ] + }, + { + name: '组织管理', + icon: 'SettingOutlined', + path: '/org', + routes: [ + { + name: '机构管理', + icon: 'smile', + path: '/org/orgamange', + component: './org/orgamange', + access: 'k2', + }, + { + name: '角色管理', + icon: 'smile', + path: '/org/roles', + component: './org/roles', + access: 'k5', + }, + { + name: '用户账号管理', + icon: 'smile', + path: '/org/users', + component: './org/users', + access: 'k5', + }, + ] + }, + { + name: '元数据管理', + icon: 'DropboxSquareFilled', + path: '/database', + routes: [ + { + name: '物料管理', + icon: 'smile', + path: '/database/basic/batching', + component: './database/basic/batching', + access: 'k7', + }, + + { + name: '商品管理', + icon: 'smile', + path: '/database', + routes: [ + { + name: '商品类型', + icon: 'smile', + path: '/database/goods/goodstypemanage', + component: './database/goods/goodstypemanage', + access: 'k7', + }, + { + name: '商品多属性', + icon: 'smile', + path: '/database/goods/goodsattribute', + component: './database/goods/goodsattribute', + access: 'k7', + }, + { + name: '商品基础信息', + icon: 'smile', + path: '/database/goods/newgoods', + component: './database/goods/newgoods', + access: 'k7', + }, + { + name: '添加商品基础信息', + icon: 'smile', + path: '/database/goods/goodsInfo', + component: './database/goods/goodsInfo', + access: 'k7', + }, + ] + }, + ], + }, + + { + name: '设备管理', + icon: 'BankFilled', + path: '/device', + routes: [ + { + name: '产品管理', + icon: 'smile', + path: '/device/deviceType', + component: './device/deviceType', + access: 'k12', + }, + { + name: '设备信息', + icon: 'smile', + path: '/device/deviceInfo', + component: './device/deviceInfo', + access: 'k14', + }, + { + name: '版本管理', + icon: 'smile', + path: '/device/deviceVesion', + component: './device/deviceVesion', + access: 'k14', + }, + // { + // name: '设备工艺信息', + // icon: 'smile', + // path: '/device/devicetechnology', + // component: './device/devicetechnology', + // access: 'k9', + // }, + // { + // name: '设备商品管理', + // icon: 'smile', + // path: '/device/deviceFood', + // component: './device/deviceFood', + // access: 'k14', + // }, + ], + }, + { + path: '/', + redirect: '/welcome', + }, + { + path: '/welcome', + name: 'welcome', + icon: 'smile', + component: './Welcome', + }, + + //什么都不要想404直接放最后 + { + component: './404', + }, +]; diff --git a/default.conf b/default.conf new file mode 100644 index 0000000..ad50602 --- /dev/null +++ b/default.conf @@ -0,0 +1,13 @@ +server { + listen 80; + server_name localhost; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + try_files $uri $uri/ /index.html; + } +} + + + diff --git a/dockerfile b/dockerfile new file mode 100644 index 0000000..70297bc --- /dev/null +++ b/dockerfile @@ -0,0 +1,5 @@ +FROM nginx +COPY ./dist /usr/share/nginx/html/ +COPY ./default.conf /etc/nginx/conf.d/ +EXPOSE 80 + diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..6410cc0 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,10 @@ +module.exports = { + testURL: 'http://localhost:7002/', + testEnvironment: './tests/PuppeteerEnvironment', + verbose: false, + extraSetupFiles: ['./tests/setupTests.js'], + globals: { + ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION: false, + localStorage: null, + }, +}; diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..f2853d7 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "baseUrl": ".", + "paths": { + "@/*": [ + "./src/*" + ] + } + } +} diff --git a/k8s_kitchenweb.yaml b/k8s_kitchenweb.yaml new file mode 100644 index 0000000..0991553 --- /dev/null +++ b/k8s_kitchenweb.yaml @@ -0,0 +1,57 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kitchenweb + namespace: kube- +spec: + + selector: + matchLabels: + app: kitchenweb + replicas: 1 + template: + metadata: + labels: + app: kitchenweb + spec: + containers: + - image: 10.2.1.24:10242/bpa/kitchenweb: + imagePullPolicy: IfNotPresent + name: kitchenweb + env: + - name: branch + value: + - name: TZ + value: Asia/Shanghai + ports: + - containerPort: 80 + protocol: TCP + volumeMounts: + - mountPath: "/etc/localtime" + name: timezone + resources: + requests: + cpu: "100m" + memory: "112Mi" + limits: + cpu: "500m" + memory: "512Mi" + volumes: + - name: timezone + hostPath: + path: /usr/share/zoneinfo/Asia/Shanghai +--- +kind: Service +apiVersion: v1 +metadata: + labels: + app: kitchenweb + name: kitchenweb + namespace: kube- +spec: + type: ClusterIP + ports: + - port: 80 + name: http + selector: + app: kitchenweb diff --git a/mock/listTableList.js b/mock/listTableList.js new file mode 100644 index 0000000..abd0748 --- /dev/null +++ b/mock/listTableList.js @@ -0,0 +1,178 @@ +// eslint-disable-next-line import/no-extraneous-dependencies +import moment from 'moment'; +import { parse } from 'url'; // mock tableListDataSource + +const genList = (current, pageSize) => { + const tableListDataSource = []; + + for (let i = 0; i < pageSize; i += 1) { + const index = (current - 1) * 10 + i; + tableListDataSource.push({ + key: index, + disabled: i % 6 === 0, + href: 'https://ant.design', + avatar: [ + 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png', + 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png', + ][i % 2], + name: `TradeCode ${index}`, + owner: '曲丽丽', + desc: '这是一段描述', + callNo: Math.floor(Math.random() * 1000), + status: Math.floor(Math.random() * 10) % 4, + updatedAt: moment().format('YYYY-MM-DD'), + createdAt: moment().format('YYYY-MM-DD'), + progress: Math.ceil(Math.random() * 100), + }); + } + + tableListDataSource.reverse(); + return tableListDataSource; +}; + +let tableListDataSource = genList(1, 100); + +function getRule(req, res, u) { + let realUrl = u; + + if (!realUrl || Object.prototype.toString.call(realUrl) !== '[object String]') { + realUrl = req.url; + } + + const { current = 1, pageSize = 10 } = req.query; + const params = parse(realUrl, true).query; + let dataSource = [...tableListDataSource].slice((current - 1) * pageSize, current * pageSize); + const sorter = JSON.parse(params.sorter || '{}'); + + if (sorter) { + dataSource = dataSource.sort((prev, next) => { + let sortNumber = 0; + Object.keys(sorter).forEach((key) => { + if (sorter[key] === 'descend') { + if (prev[key] - next[key] > 0) { + sortNumber += -1; + } else { + sortNumber += 1; + } + + return; + } + + if (prev[key] - next[key] > 0) { + sortNumber += 1; + } else { + sortNumber += -1; + } + }); + return sortNumber; + }); + } + + if (params.filter) { + const filter = JSON.parse(params.filter); + + if (Object.keys(filter).length > 0) { + dataSource = dataSource.filter((item) => { + return Object.keys(filter).some((key) => { + if (!filter[key]) { + return true; + } + + if (filter[key].includes(`${item[key]}`)) { + return true; + } + + return false; + }); + }); + } + } + + if (params.name) { + dataSource = dataSource.filter((data) => data?.name?.includes(params.name || '')); + } + + const result = { + data: dataSource, + total: tableListDataSource.length, + success: true, + pageSize, + current: parseInt(`${params.current}`, 10) || 1, + }; + return res.json(result); +} + +function postRule(req, res, u, b) { + let realUrl = u; + + if (!realUrl || Object.prototype.toString.call(realUrl) !== '[object String]') { + realUrl = req.url; + } + + const body = (b && b.body) || req.body; + const { method, name, desc, key } = body; + + switch (method) { + /* eslint no-case-declarations:0 */ + case 'delete': + tableListDataSource = tableListDataSource.filter((item) => key.indexOf(item.key) === -1); + break; + + case 'post': + (() => { + const i = Math.ceil(Math.random() * 10000); + const newRule = { + key: tableListDataSource.length, + href: 'https://ant.design', + avatar: [ + 'https://gw.alipayobjects.com/zos/rmsportal/eeHMaZBwmTvLdIwMfBpg.png', + 'https://gw.alipayobjects.com/zos/rmsportal/udxAbMEhpwthVVcjLXik.png', + ][i % 2], + name, + owner: '曲丽丽', + desc, + callNo: Math.floor(Math.random() * 1000), + status: Math.floor(Math.random() * 10) % 2, + updatedAt: moment().format('YYYY-MM-DD'), + createdAt: moment().format('YYYY-MM-DD'), + progress: Math.ceil(Math.random() * 100), + }; + tableListDataSource.unshift(newRule); + return res.json(newRule); + })(); + + return; + + case 'update': + (() => { + let newRule = {}; + tableListDataSource = tableListDataSource.map((item) => { + if (item.key === key) { + newRule = { ...item, desc, name }; + return { ...item, desc, name }; + } + + return item; + }); + return res.json(newRule); + })(); + + return; + + default: + break; + } + + const result = { + list: tableListDataSource, + pagination: { + total: tableListDataSource.length, + }, + }; + res.json(result); +} + +export default { + 'GET /api/rule': getRule, + 'POST /api/rule': postRule, +}; diff --git a/mock/notices.js b/mock/notices.js new file mode 100644 index 0000000..851e8cd --- /dev/null +++ b/mock/notices.js @@ -0,0 +1,105 @@ +const getNotices = (req, res) => { + res.json({ + data: [ + { + id: '000000001', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png', + title: '你收到了 14 份新周报', + datetime: '2017-08-09', + type: 'notification', + }, + { + id: '000000002', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/OKJXDXrmkNshAMvwtvhu.png', + title: '你推荐的 曲妮妮 已通过第三轮面试', + datetime: '2017-08-08', + type: 'notification', + }, + { + id: '000000003', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/kISTdvpyTAhtGxpovNWd.png', + title: '这种模板可以区分多种通知类型', + datetime: '2017-08-07', + read: true, + type: 'notification', + }, + { + id: '000000004', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/GvqBnKhFgObvnSGkDsje.png', + title: '左侧图标用于区分不同的类型', + datetime: '2017-08-07', + type: 'notification', + }, + { + id: '000000005', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/ThXAXghbEsBCCSDihZxY.png', + title: '内容不要超过两行字,超出时自动截断', + datetime: '2017-08-07', + type: 'notification', + }, + { + id: '000000006', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg', + title: '曲丽丽 评论了你', + description: '描述信息描述信息描述信息', + datetime: '2017-08-07', + type: 'message', + clickClose: true, + }, + { + id: '000000007', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg', + title: '朱偏右 回复了你', + description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像', + datetime: '2017-08-07', + type: 'message', + clickClose: true, + }, + { + id: '000000008', + avatar: 'https://gw.alipayobjects.com/zos/rmsportal/fcHMVNCjPOsbUGdEduuv.jpeg', + title: '标题', + description: '这种模板用于提醒谁与你发生了互动,左侧放『谁』的头像', + datetime: '2017-08-07', + type: 'message', + clickClose: true, + }, + { + id: '000000009', + title: '任务名称', + description: '任务需要在 2017-01-12 20:00 前启动', + extra: '未开始', + status: 'todo', + type: 'event', + }, + { + id: '000000010', + title: '第三方紧急代码变更', + description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务', + extra: '马上到期', + status: 'urgent', + type: 'event', + }, + { + id: '000000011', + title: '信息安全考试', + description: '指派竹尔于 2017-01-09 前完成更新并发布', + extra: '已耗时 8 天', + status: 'doing', + type: 'event', + }, + { + id: '000000012', + title: 'ABCD 版本发布', + description: '冠霖提交于 2017-01-06,需在 2017-01-07 前完成代码变更任务', + extra: '进行中', + status: 'processing', + type: 'event', + }, + ], + }); +}; + +export default { + 'GET /kitchen/api/notices': getNotices, +}; diff --git a/mock/route.js b/mock/route.js new file mode 100644 index 0000000..93dca74 --- /dev/null +++ b/mock/route.js @@ -0,0 +1,7 @@ +export default { + '/saasbase/api/auth_routes': { + '/form/advanced-form': { + authority: ['admin', 'user'], + }, + }, +}; diff --git a/mock/user.js b/mock/user.js new file mode 100644 index 0000000..436f62d --- /dev/null +++ b/mock/user.js @@ -0,0 +1,207 @@ +const waitTime = (time = 100) => { + return new Promise((resolve) => { + setTimeout(() => { + resolve(true); + }, time); + }); +}; + +async function getFakeCaptcha(req, res) { + await waitTime(2000); + return res.json('captcha-xxx'); +} + +const { ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION } = process.env; +/** + * 当前用户的权限,如果为空代表没登录 + * current user access, if is '', user need login + * 如果是 pro 的预览,默认是有权限的 + */ + +let access = ANT_DESIGN_PRO_ONLY_DO_NOT_USE_IN_YOUR_PRODUCTION === 'site' ? 'admin' : ''; + +const getAccess = () => { + return access; +}; // 代码中会兼容本地 service mock 以及部署站点的静态数据 + +export default { + // 支持值为 Object 和 Array + 'GET /kitchen/api/currentUser': (req, res) => { + if (!getAccess()) { + res.status(401).send({ + data: { + isLogin: false, + }, + errorCode: '401', + errorMessage: '请先登录!', + success: true, + }); + return; + } + + res.send({ + name: 'Serati Ma', + avatar: 'https://gw.alipayobjects.com/zos/antfincdn/XAosXuNZyF/BiazfanxmamNRoxxVxka.png', + userid: '00000001', + email: 'antdesign@alipay.com', + signature: '海纳百川,有容乃大', + title: '交互专家', + group: '蚂蚁金服-某某某事业群-某某平台部-某某技术部-UED', + tags: [ + { + key: '0', + label: '很有想法的', + }, + { + key: '1', + label: '专注设计', + }, + { + key: '2', + label: '辣~', + }, + { + key: '3', + label: '大长腿', + }, + { + key: '4', + label: '川妹子', + }, + { + key: '5', + label: '海纳百川', + }, + ], + notifyCount: 12, + unreadCount: 11, + country: 'China', + access: getAccess(), + geographic: { + province: { + label: '浙江省', + key: '330000', + }, + city: { + label: '杭州市', + key: '330100', + }, + }, + address: '西湖区工专路 77 号', + phone: '0752-268888888', + }); + }, + // GET POST 可省略 + 'GET /kitchen/api/users': [ + { + key: '1', + name: 'John Brown', + age: 32, + address: 'New York No. 1 Lake Park', + }, + { + key: '2', + name: 'Jim Green', + age: 42, + address: 'London No. 1 Lake Park', + }, + { + key: '3', + name: 'Joe Black', + age: 32, + address: 'Sidney No. 1 Lake Park', + }, + ], + 'POST /kitchen/api/login/account': async (req, res) => { + const { password, username, type } = req.body; + await waitTime(2000); + + if (password === 'ant.design' && username === 'admin') { + res.send({ + status: 'ok', + type, + currentAuthority: 'admin', + }); + access = 'admin'; + return; + } + + if (password === 'ant.design' && username === 'user') { + res.send({ + status: 'ok', + type, + currentAuthority: 'user', + }); + access = 'user'; + return; + } + + if (type === 'mobile') { + res.send({ + status: 'ok', + type, + currentAuthority: 'admin', + }); + access = 'admin'; + return; + } + + res.send({ + status: 'error', + type, + currentAuthority: 'guest', + }); + access = 'guest'; + }, + 'POST /kitchen/api/login/outLogin': (req, res) => { + access = ''; + res.send({ + data: {}, + success: true, + }); + }, + 'POST /kitchen/api/register': (req, res) => { + res.send({ + status: 'ok', + currentAuthority: 'user', + success: true, + }); + }, + 'GET /kitchen/api/500': (req, res) => { + res.status(500).send({ + timestamp: 1513932555104, + status: 500, + error: 'error', + message: 'error', + path: '/base/category/list', + }); + }, + 'GET /kitchen/api/404': (req, res) => { + res.status(404).send({ + timestamp: 1513932643431, + status: 404, + error: 'Not Found', + message: 'No message available', + path: '/base/category/list/2121212', + }); + }, + 'GET /kitchen/api/403': (req, res) => { + res.status(403).send({ + timestamp: 1513932555104, + status: 403, + error: 'Unauthorized', + message: 'Unauthorized', + path: '/base/category/list', + }); + }, + 'GET /kitchen/api/401': (req, res) => { + res.status(401).send({ + timestamp: 1513932555104, + status: 401, + error: 'Unauthorized', + message: 'Unauthorized', + path: '/base/category/list', + }); + }, + 'GET /kitchen/api/login/captcha': getFakeCaptcha, +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..91ea2d7 --- /dev/null +++ b/package.json @@ -0,0 +1,129 @@ +{ + "name": "ant-design-pro", + "version": "5.0.0", + "private": true, + "description": "An out-of-box UI solution for enterprise applications", + "scripts": { + "analyze": "cross-env ANALYZE=1 umi build", + "build": "umi build", + "deploy": "npm run build && npm run gh-pages", + "dev": "npm run start:dev", + "gh-pages": "gh-pages -d dist", + "i18n-remove": "pro i18n-remove --locale=zh-CN --write", + "postinstall": "umi g tmp", + "lint": "umi g tmp && npm run lint:js && npm run lint:style && npm run lint:prettier", + "lint-staged": "lint-staged", + "lint-staged:js": "eslint --ext .js,.jsx,.ts,.tsx ", + "lint:fix": "eslint --fix --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src && npm run lint:style", + "lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src", + "lint:prettier": "prettier -c --write \"src/**/*\" --end-of-line auto", + "lint:style": "stylelint --fix \"src/**/*.less\" --syntax less", + "openapi": "umi openapi", + "precommit": "lint-staged", + "prettier": "prettier -c --write \"src/**/*\"", + "start": "cross-env UMI_ENV=dev umi dev", + "start:umi-ui": "HOST=0.0.0.0 UMI-UI=1 umi dev", + "start:dev": "cross-env REACT_APP_ENV=dev MOCK=none UMI_ENV=dev umi dev", + "start:no-mock": "cross-env MOCK=none UMI_ENV=dev umi dev", + "start:no-ui": "cross-env UMI_UI=none UMI_ENV=dev umi dev", + "start:pre": "cross-env REACT_APP_ENV=pre UMI_ENV=dev umi dev", + "start:test": "cross-env REACT_APP_ENV=test MOCK=none UMI_ENV=dev umi dev", + "pretest": "node ./tests/beforeTest", + "test": "umi test", + "test:all": "node ./tests/run-tests.js", + "test:component": "umi test ./src/components", + "serve": "umi-serve", + "tsc": "tsc --noEmit" + }, + "lint-staged": { + "**/*.less": "stylelint --syntax less", + "**/*.{js,jsx,ts,tsx}": "npm run lint-staged:js", + "**/*.{js,jsx,tsx,ts,less,md,json}": [ + "prettier --write" + ] + }, + "browserslist": [ + "> 1%", + "last 2 versions", + "not ie <= 10" + ], + "dependencies": { + "@ant-design/charts": "^1.2.14", + "@ant-design/icons": "^4.5.0", + "@ant-design/pro-card": "^1.18.0", + "@ant-design/pro-descriptions": "^1.10.0", + "@ant-design/pro-form": "^1.48.0", + "@ant-design/pro-layout": "^6.29.0", + "@ant-design/pro-list": "^1.21.37", + "@ant-design/pro-table": "^2.57.0", + "@ant-design/pro-utils": "^1.28.0", + "@umijs/route-utils": "^2.0.3", + "@wangeditor/editor": "^5.1.15", + "@wangeditor/editor-for-react": "^1.0.6", + "antd": "^4.17.0", + "axios": "^0.26.1", + "braft-editor": "^2.3.9", + "classnames": "^2.2.6", + "cos-js-sdk-v5": "^1.3.5", + "echarts": "^5.3.3", + "js-base64": "^3.7.5", + "js-export-excel": "^1.1.4", + "linq": "^4.0.0", + "lodash": "^4.17.11", + "moment": "^2.25.3", + "nanoid": "^4.0.2", + "omit.js": "^2.0.2", + "qrcode.react": "^1.0.1", + "react": "^17.0.0", + "react-custom-scrollbar": "^1.0.0", + "react-custom-scrollbars": "^4.2.1", + "react-dev-inspector": "^1.1.1", + "react-dom": "^17.0.0", + "react-helmet-async": "^1.0.4", + "swagger-ui-react": "^4.14.0", + "umi": "^3.5.0", + "umi-serve": "^1.9.10" + }, + "devDependencies": { + "@ant-design/pro-cli": "^2.0.2", + "@types/express": "^4.17.0", + "@types/history": "^4.7.2", + "@types/jest": "^27.0.2", + "@types/lodash": "^4.14.177", + "@types/react": "^17.0.35", + "@types/react-dom": "^17.0.0", + "@types/react-helmet": "^6.1.0", + "@umijs/fabric": "^2.6.2", + "@umijs/openapi": "^1.3.6", + "@umijs/plugin-blocks": "^2.0.5", + "@umijs/plugin-esbuild": "^1.0.1", + "@umijs/plugin-openapi": "^1.2.0", + "@umijs/preset-ant-design-pro": "^1.2.0", + "@umijs/preset-dumi": "^1.1.32", + "@umijs/preset-react": "^1.8.27", + "@umijs/preset-ui": "^2.2.9", + "@umijs/yorkie": "^2.0.3", + "carlo": "^0.9.46", + "cross-env": "^7.0.0", + "cross-port-killer": "^1.1.1", + "detect-installer": "^1.0.1", + "enzyme": "^3.11.0", + "eslint": "^8.2.0", + "eslint-plugin-react": "^7.29.4", + "express": "^4.17.1", + "gh-pages": "^3.0.0", + "jsdom-global": "^3.0.2", + "lint-staged": "^12.0.2", + "mockjs": "^1.0.1-beta3", + "prettier": "^2.3.2", + "puppeteer-core": "^11.0.0", + "stylelint": "^14.1.0", + "typescript": "^4.2.2" + }, + "engines": { + "node": ">=10.0.0" + }, + "gitHooks": { + "commit-msg": "fabric verify-commit" + } +} diff --git a/public/CNAME b/public/CNAME new file mode 100644 index 0000000..30c2d4d --- /dev/null +++ b/public/CNAME @@ -0,0 +1 @@ +preview.pro.ant.design \ No newline at end of file diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..e2e9325 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/icons/icon-128x128.png b/public/icons/icon-128x128.png new file mode 100644 index 0000000..48d0e23 Binary files /dev/null and b/public/icons/icon-128x128.png differ diff --git a/public/icons/icon-192x192.png b/public/icons/icon-192x192.png new file mode 100644 index 0000000..938e9b5 Binary files /dev/null and b/public/icons/icon-192x192.png differ diff --git a/public/icons/icon-512x512.png b/public/icons/icon-512x512.png new file mode 100644 index 0000000..21fc108 Binary files /dev/null and b/public/icons/icon-512x512.png differ diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000..d0b98c5 Binary files /dev/null and b/public/logo.png differ diff --git a/public/logo.svg b/public/logo.svg new file mode 100644 index 0000000..14d453c --- /dev/null +++ b/public/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/public/pro_icon.svg b/public/pro_icon.svg new file mode 100644 index 0000000..e075b78 --- /dev/null +++ b/public/pro_icon.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/access.js b/src/access.js new file mode 100644 index 0000000..530d028 --- /dev/null +++ b/src/access.js @@ -0,0 +1,50 @@ +/** + * 这里是把登录信息拿来做菜单权限控制 + * @see https://umijs.org/zh-CN/plugins/plugin-access + * */ +// permission 按钮权限标志 +// function checkPermission(currentUser:API.CurrentUser,permission:string) +// { +// return currentUser&& currentUser.data.roles.some( +// (roles)=>roles.permissions.map(permission=>permission.name).indexof(permission)>-1) +// } +export default function access(initialState) { + const { currentUser, menuData } = initialState || {}; + + return { + // k1:true, + // k2:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k2'): false, + // k3:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k3'): false, + // k4:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k4'): false, + // k5:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k5'): false, + // k6:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k6'): false, + // k7:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k7'): false, + // k8:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k8'): false, + // k9:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k9'): false, + // k10:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k10'): false, + // k11:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k11'): false, + // k12:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k12'): false, + // k13:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k13'): false, + // k14:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k14'): false, + // k15:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k15'): false, + // k16:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k16'): false, + // k17:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k17'): false, + // k18:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k18'): false, + // k19:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k19'): false, + // k20:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k20'): false, + // k21:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k21'): false, + // k22:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k22'): false, + // k23:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k23'): false, + // k24:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k24'): false, + // k25:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k25'): false, + // k26:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k26'): false, + // k27:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k27'): false, + // k28:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k28'): false, + // k29:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k29'): false, + // k30:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k30'): false, + // k31:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k31'): false, + // k32:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k32'): false, + // k33:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k33'): false, + // k34:dymicMenu!=undefined? dymicMenu.data.some(t=>t.access=='k34'): false, + }; +} diff --git a/src/app.jsx b/src/app.jsx new file mode 100644 index 0000000..3b564cd --- /dev/null +++ b/src/app.jsx @@ -0,0 +1,467 @@ +import React from 'react'; +import { PageLoading } from '@ant-design/pro-layout'; +import { notification } from 'antd'; +import { history, Link, RequestConfig } from 'umi'; +import RightContent from '@/components/RightContent'; +import Footer from '@/components/Footer'; +import TagView from '@/components/TagView'; +import * as Icon from '@ant-design/icons'; +import api from '@/services/api'; +const isDev = process.env.NODE_ENV === 'development'; +const loginPath = '/user/login'; +/** 获取用户信息比较慢的时候会展示一个 loading */ + +export const initialStateConfig = { + loading: , +}; +/** + * @see https://umijs.org/zh-CN/plugins/plugin-initial-state + * */ + +export async function getInitialState() { + const fetchUserInfo = async () => { + try { + const currentUser = await api.queryCurrent(); + + if (currentUser.data == null && history.location.pathname !== '/gateAdmin') { + history.push(loginPath); + } + return currentUser; + } catch (error) { + const { location } = history; // 如果没有登录,重定向到 login + if (location.pathname != loginPath && history.location.pathname !== '/gateAdmin') { + history.push(loginPath); + } + } + + return undefined; + }; + const queryMenuData = async () => { + try { + const data = [ + { + path: '/welcome', + name: '连锁经营平台', + icon: 'smile', + hideInMenu: true, + component: './Welcome', + }, + { + code: 'sys', + name: '系统管理', + icon: 'SettingOutlined', + path: '/sys', + routes: [ + { + code: 'Menus', + name: '系统菜单', + icon: 'smile', + path: '/sys/Menus', + component: './sys/Menus', + access: 'k6', + }, + // { + // code: 'dictdata', + // name: '字典信息', + // icon: 'smile', + // path: '/sys/dictionary/dictdata', + // component: './sys/dictionary/dictdata', + // access: 'k6', + // }, + { + code: 'dicttype', + name: '字典类型', + icon: 'smile', + path: '/sys/dictionary/dicttype', + component: './sys/dictionary/dicttype', + access: 'k6', + }, + // { + // code: 'Log', + // name: '操作日志', + // icon: 'smile', + // path: '/sys/Log', + // component: './sys/Log', + // access: 'k3', + // }, + // { + // code: 'Log', + // name: '错误日志', + // icon: 'smile', + // path: '/sys/errLog', + // component: './sys/errLog', + // access: 'k3', + // }, + ], + }, + { + code: 'company', + name: '加盟商管理', + icon: 'TeamOutlined', + path: '/company', + routes: [ + { + code: 'account', + name: '账号管理', + icon: 'smile', + path: '/company/account', + component: './sys/account', + access: 'k4', + }, + ] + }, + { + code: 'orgamange', + name: '组织管理', + icon: 'ClusterOutlined', + path: '/org', + routes: [ + { + code: 'Org', + name: '机构管理', + icon: 'smile', + path: '/org/orgamange', + component: './org/orgamange', + access: 'k2', + }, + { + code: 'roles', + name: '角色管理', + icon: 'smile', + path: '/org/Roles', + component: './org/Roles', + access: 'k2', + }, + { + code: 'users', + name: '用户账号管理', + icon: 'smile', + path: '/org/users', + component: './org/users', + access: 'k2', + }, + ] + }, + { + code: 'device', + name: '设备管理', + icon: 'PrinterOutlined', + path: '/device', + routes: [ + { + code: 'deviceType', + name: '产品管理', + icon: 'smile', + path: '/device/deviceType', + component: './device/deviceType', + access: 'k12', + }, + { + code: 'deviceInfo', + name: '设备信息', + icon: 'smile', + path: '/device/deviceInfo', + component: './device/deviceInfo', + access: 'k14', + }, + { + code: 'deviceVesion', + name: '版本管理', + icon: 'smile', + path: '/device/deviceVesion', + component: './device/deviceVesion', + access: 'k14', + }, + // { + // code: 'devicetechnology', + // name: '设备工艺信息', + // icon: 'smile', + // path: '/device/devicetechnology', + // component: './device/devicetechnology', + // access: 'k7', + // }, + // { + // code: 'deviceFood', + // name: '设备商品管理', + // icon: 'smile', + // path: '/device/deviceFood', + // component: './device/deviceFood', + // access: 'k14', + // }, + + ], + }, + { + + code: 'database', + name: '元数据管理', + icon: 'DatabaseOutlined', + path: '/database', + routes:[ + { + code: 'batching', + name: '物料管理', + icon: 'smile', + path: '/basic', + routes:[ + { + code: 'batching', + name: '物料基础信息', + icon: 'smile', + path: '/database/basic/batching', + component: './database/basic/batching', + access: 'k7', + }, + ] + }, + { + code: 'goods', + name: '商品管理', + icon: 'smile', + path: '/goods', + routes:[ + { + code: 'goods-type', + name: '商品类型', + icon: 'smile', + path: '/database/goods/goodstypemanage', + component: './database/goods/goodstypemanage', + access: 'k11', + }, + { + code: 'goodsattribute', + name: '商品属性', + icon: 'smile', + path: '/database/goods/goodsattribute', + component: './database/goods/goodsattribute', + access: 'k10', + }, + { + code: 'newgoods', + name: '商品基础信息', + icon: 'smile', + path: '/database/goods/newgoods', + component: './database/goods/newgoods', + access: 'k10', + }, + ] + }, + ] + }, + ]; + // api.queryMenus(); + return data; + } catch (error) { + history.push(loginPath); + } + return []; + }; + // 如果是登录页面,不执行 + if (history.location.pathname !== loginPath) { + const currentUser = await fetchUserInfo(); + var tempMenu = await queryMenuData(); + //创建菜单 + //await syncMenus(tempMenu); + if (!isDev) { + var data = await dymicMenus(currentUser.data.id); + tempMenu = data.data; + } + + return { + fetchUserInfo, + currentUser, + menuData: tempMenu, + settings: {}, + }; + } + return { + fetchUserInfo, + settings: {}, + }; +} + +/** + * 同步菜单 + * @param {*} args + * @returns + */ +const syncMenus = async (args) => { + return await api.queryAndSyncMenu({ json: JSON.stringify(args) }); +}; + +/** + * 动态菜单 + * @param {*} userid + * @returns + */ + +const dymicMenus = async (userid) => { + return await api.DymicMenus(userid); +}; + +/** + * + * 动态路由 + * + */ +const loopMenuItem = (menus) => + menus?.map(({ icon, children, ...item }) => { + if (typeof icon != 'undefined' && Icon[icon] != undefined) { + return { + ...item, + icon: icon && React.createElement(Icon[icon]), + children: children && loopMenuItem(children), + }; + } else { + return { + ...item, + children: children && loopMenuItem(children), + }; + } + }); +/** + * 异常处理程序 + 200: '服务器成功返回请求的数据。', + 201: '新建或修改数据成功。', + 202: '一个请求已经进入后台排队(异步任务)。', + 204: '删除数据成功。', + 400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。', + 401: '用户没有权限(令牌、用户名、密码错误)。', + 403: '用户得到授权,但是访问是被禁止的。', + 404: '发出的请求针对的是不存在的记录,服务器没有进行操作。', + 405: '请求方法不被允许。', + 406: '请求的格式不可得。', + 410: '请求的资源被永久删除,且不会再得到的。', + 422: '当创建一个对象时,发生一个验证错误。', + 500: '服务器发生错误,请检查服务器。', + 502: '网关错误。', + 503: '服务不可用,服务器暂时过载或维护。', + 504: '网关超时。', + //-----English + 200: The server successfully returned the requested data. ', + 201: New or modified data is successful. ', + 202: A request has entered the background queue (asynchronous task). ', + 204: Data deleted successfully. ', + 400: 'There was an error in the request sent, and the server did not create or modify data. ', + 401: The user does not have permission (token, username, password error). ', + 403: The user is authorized, but access is forbidden. ', + 404: The request sent was for a record that did not exist. ', + 405: The request method is not allowed. ', + 406: The requested format is not available. ', + 410': + 'The requested resource is permanently deleted and will no longer be available. ', + 422: When creating an object, a validation error occurred. ', + 500: An error occurred on the server, please check the server. ', + 502: Gateway error. ', + 503: The service is unavailable. ', + 504: The gateway timed out. ', + * @see https://beta-pro.ant.design/docs/request-cn + */ +const codeMessage = { + 200: '服务器成功返回请求的数据。', + 201: '新建或修改数据成功。', + 202: '一个请求已经进入后台排队(异步任务)。', + 204: '删除数据成功。', + 400: '发出的请求有错误,服务器没有进行新建或修改数据的操作。', + 401: '用户没有权限(令牌、用户名、密码错误)。', + 403: '用户得到授权,但是访问是被禁止的。', + 404: '发出的请求针对的是不存在的记录,服务器没有进行操作。', + 405: '请求方法不被允许。', + 406: '请求的格式不可得。', + 410: '请求的资源被永久删除,且不会再得到的。', + 422: '当创建一个对象时,发生一个验证错误。', + 500: '服务器发生错误,请检查服务器。', + 502: '网关错误。', + 503: '服务不可用,服务器暂时过载或维护。', + 504: '网关超时。', +}; + +export const request = { + + errorHandler: (error) => { + const { response } = error; + console.log('response', response); + if (response && response.status !== 200 && response.status !== 422) { + const errorText = codeMessage[response.status] || response.statusText; + const { status, url } = response; + if (response.status === 401 || response.status === 403) { + notification.error({ + description: '请先登录。', + message: '未登录', + }); + // history.push('/user/login'); + const { location } = history; // 如果没有登录,重定向到 login + if (!location.pathname.includes(loginPath) && history.location.pathname !== '/gateAdmin') { + history.push(loginPath); + } + } else { + notification.error({ + description: '网络发生异常,无法连接服务器', + message: '网络异常', + }); + } + } + if (!response) { + notification.error({ + description: '网络发生异常,无法连接服务器', + message: '网络异常', + }); + } + + throw error; + }, + //prefix: `${DOMAIN}`, + requestInterceptors: [ + (url, options) => { + url = decodeURI(encodeURI(url).replace(/%E2%80%8B/g, '')); + const newOptions = { ...options }; + const auttoken = localStorage.getItem('token'); + const userid = localStorage.getItem('userid'); + newOptions.headers = { + ...newOptions.headers, + userid: userid, + Authorization: 'Bearer ' + auttoken, + LoginType: 1, + Accept: 'application/json', + 'Content-Type': 'application/json; charset=utf-8', + }; + return { url, options: newOptions }; + }, + ], +}; +// ProLayout 支持的api https://procomponents.ant.design/components/layout + +export const layout = ({ initialState }) => { + return { + rightContentRender: () => , + disableContentMargin: false, + waterMarkProps: { + content: '黑菠萝技术部', + }, + + footerRender: () =>