From d10e80bf83ad4d0f634bdaa381ae8a801777fc6e Mon Sep 17 00:00:00 2001 From: xiaojunnuo Date: Sun, 29 Jan 2023 15:26:45 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=B1:=20[client]=20sync=20upgrade=20wit?= =?UTF-8?q?h=2021=20commits=20[trident-sync]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update README.md --- .gitignore | 29 +- packages/ui/certd-client/.browserslistrc | 3 + packages/ui/certd-client/.env | 3 + packages/ui/certd-client/.env.debug | 2 + packages/ui/certd-client/.env.debugpm | 2 + packages/ui/certd-client/.env.pm | 2 + packages/ui/certd-client/.env.production | 3 + packages/ui/certd-client/.eslintignore | 2 + packages/ui/certd-client/.eslintrc.js | 76 +++ packages/ui/certd-client/.gitignore | 11 + packages/ui/certd-client/.npmignore | 2 + packages/ui/certd-client/.prettierrc | 5 + packages/ui/certd-client/CHANGELOG.md | 12 + packages/ui/certd-client/LICENSE | 21 + packages/ui/certd-client/README.md | 37 + packages/ui/certd-client/build/modify-vars.ts | 11 + .../ui/certd-client/build/theme-colors.ts | 72 ++ .../ui/certd-client/build/theme-plugin.ts | 68 ++ packages/ui/certd-client/index.html | 26 + packages/ui/certd-client/package.json | 120 ++++ packages/ui/certd-client/public/favicon.ico | Bin 0 -> 4286 bytes .../public/images/logo-certd/logo.svg | 7 + .../public/images/logo-certd/rect-black.svg | 44 ++ .../public/images/logo-certd/rect.svg | 44 ++ .../public/images/logo-certd/square.svg | 17 + .../certd-client/public/images/logo/logo.svg | 7 + .../public/images/logo/rect-black.svg | 108 +++ .../certd-client/public/images/logo/rect.svg | 44 ++ .../public/images/logo/square.svg | 106 +++ packages/ui/certd-client/public/index.css | 12 + packages/ui/certd-client/public/index.html | 17 + packages/ui/certd-client/public/logo.svg | 106 +++ packages/ui/certd-client/src/App.vue | 56 ++ .../src/api/modules/api.user.mock.ts | 31 + .../certd-client/src/api/modules/api.user.ts | 51 ++ packages/ui/certd-client/src/api/service.ts | 138 ++++ packages/ui/certd-client/src/api/tools.ts | 66 ++ .../ui/certd-client/src/assets/background.svg | 69 ++ packages/ui/certd-client/src/assets/logo.png | Bin 0 -> 6849 bytes .../src/components/highlight-styles/agate.css | 108 +++ .../highlight-styles/androidstudio.css | 66 ++ .../highlight-styles/arduino-light.css | 88 +++ .../src/components/highlight-styles/arta.css | 73 ++ .../components/highlight-styles/ascetic.css | 45 ++ .../highlight-styles/atelier-cave-dark.css | 83 +++ .../highlight-styles/atelier-cave-light.css | 85 +++ .../highlight-styles/atelier-dune-dark.css | 69 ++ .../highlight-styles/atelier-dune-light.css | 69 ++ .../highlight-styles/atelier-estuary-dark.css | 84 +++ .../atelier-estuary-light.css | 84 +++ .../highlight-styles/atelier-forest-dark.css | 69 ++ .../highlight-styles/atelier-forest-light.css | 69 ++ .../highlight-styles/atelier-heath-dark.css | 69 ++ .../highlight-styles/atelier-heath-light.css | 69 ++ .../atelier-lakeside-dark.css | 69 ++ .../atelier-lakeside-light.css | 69 ++ .../highlight-styles/atelier-plateau-dark.css | 84 +++ .../atelier-plateau-light.css | 84 +++ .../highlight-styles/atelier-savanna-dark.css | 84 +++ .../atelier-savanna-light.css | 84 +++ .../highlight-styles/atelier-seaside-dark.css | 69 ++ .../atelier-seaside-light.css | 69 ++ .../atelier-sulphurpool-dark.css | 69 ++ .../atelier-sulphurpool-light.css | 69 ++ .../highlight-styles/atom-one-dark.css | 96 +++ .../highlight-styles/atom-one-light.css | 96 +++ .../highlight-styles/brown-paper.css | 64 ++ .../highlight-styles/brown-papersq.png | Bin 0 -> 18198 bytes .../highlight-styles/codepen-embed.css | 60 ++ .../highlight-styles/color-brewer.css | 71 ++ .../components/highlight-styles/darcula.css | 77 +++ .../src/components/highlight-styles/dark.css | 63 ++ .../components/highlight-styles/darkula.css | 6 + .../components/highlight-styles/default.css | 99 +++ .../src/components/highlight-styles/docco.css | 97 +++ .../components/highlight-styles/dracula.css | 76 +++ .../src/components/highlight-styles/far.css | 71 ++ .../highlight-styles/foundation.css | 88 +++ .../highlight-styles/github-gist.css | 71 ++ .../components/highlight-styles/github.css | 99 +++ .../highlight-styles/googlecode.css | 89 +++ .../components/highlight-styles/grayscale.css | 101 +++ .../highlight-styles/gruvbox-dark.css | 108 +++ .../highlight-styles/gruvbox-light.css | 108 +++ .../components/highlight-styles/hopscotch.css | 83 +++ .../components/highlight-styles/hybrid.css | 102 +++ .../src/components/highlight-styles/idea.css | 97 +++ .../components/highlight-styles/ir-black.css | 73 ++ .../highlight-styles/kimbie.dark.css | 74 ++ .../highlight-styles/kimbie.light.css | 74 ++ .../components/highlight-styles/magula.css | 70 ++ .../components/highlight-styles/mono-blue.css | 59 ++ .../highlight-styles/monokai-sublime.css | 83 +++ .../components/highlight-styles/monokai.css | 70 ++ .../components/highlight-styles/obsidian.css | 88 +++ .../src/components/highlight-styles/ocean.css | 74 ++ .../highlight-styles/paraiso-dark.css | 72 ++ .../highlight-styles/paraiso-light.css | 72 ++ .../components/highlight-styles/pojoaque.css | 83 +++ .../components/highlight-styles/pojoaque.jpg | Bin 0 -> 1186 bytes .../components/highlight-styles/purebasic.css | 96 +++ .../highlight-styles/qtcreator_dark.css | 83 +++ .../highlight-styles/qtcreator_light.css | 83 +++ .../highlight-styles/railscasts.css | 106 +++ .../components/highlight-styles/rainbow.css | 85 +++ .../components/highlight-styles/routeros.css | 108 +++ .../highlight-styles/school-book.css | 72 ++ .../highlight-styles/school-book.png | Bin 0 -> 486 bytes .../highlight-styles/solarized-dark.css | 84 +++ .../highlight-styles/solarized-light.css | 84 +++ .../components/highlight-styles/sunburst.css | 102 +++ .../highlight-styles/tomorrow-night-blue.css | 75 +++ .../tomorrow-night-bright.css | 74 ++ .../tomorrow-night-eighties.css | 74 ++ .../highlight-styles/tomorrow-night.css | 75 +++ .../components/highlight-styles/tomorrow.css | 72 ++ .../src/components/highlight-styles/vs.css | 68 ++ .../components/highlight-styles/vs2015.css | 115 ++++ .../src/components/highlight-styles/xcode.css | 93 +++ .../src/components/highlight-styles/xt256.css | 92 +++ .../components/highlight-styles/zenburn.css | 80 +++ .../src/components/highlight/index.vue | 66 ++ .../components/highlight/libs/htmlFormat.js | 365 ++++++++++ .../ui/certd-client/src/components/index.ts | 7 + packages/ui/certd-client/src/i18n/index.ts | 27 + .../ui/certd-client/src/i18n/locale/en.ts | 3 + .../ui/certd-client/src/i18n/locale/zh_CN.ts | 9 + .../components/contentmenuList/index.vue | 56 ++ .../layout/components/contextmenu/index.vue | 68 ++ .../src/layout/components/locale/index.vue | 76 +++ .../src/layout/components/menu/index.jsx | 224 ++++++ .../src/layout/components/menu/index.less | 11 + .../layout/components/source-link/index.vue | 54 ++ .../src/layout/components/tabs/index.vue | 295 ++++++++ .../layout/components/theme/color-picker.vue | 101 +++ .../src/layout/components/theme/index.vue | 51 ++ .../src/layout/components/user-info/index.vue | 40 ++ .../src/layout/layout-framework.vue | 230 +++++++ .../src/layout/layout-outside.vue | 154 +++++ .../certd-client/src/layout/layout-pass.vue | 3 + packages/ui/certd-client/src/main.ts | 23 + packages/ui/certd-client/src/mock/base.js | 280 ++++++++ .../src/mock/common/cascader-data.js | 268 ++++++++ .../certd-client/src/mock/common/mock.dict.js | 123 ++++ .../src/mock/common/pca-data-little.js | 70 ++ .../certd-client/src/mock/common/pcas-data.js | 87 +++ packages/ui/certd-client/src/mock/index.js | 49 ++ .../src/plugin/fast-crud/index.tsx | 245 +++++++ .../src/plugin/iconfont/iconfont.js | 1 + .../certd-client/src/plugin/iconfont/index.ts | 1 + .../certd-client/src/plugin/iconify/index.ts | 2 + packages/ui/certd-client/src/plugin/index.ts | 12 + .../certd-client/src/plugin/permission/api.ts | 10 + .../src/plugin/permission/directive/index.js | 9 + .../plugin/permission/directive/permission.js | 11 + .../src/plugin/permission/errors.ts | 5 + .../src/plugin/permission/hook.ts | 45 ++ .../src/plugin/permission/index.ts | 23 + .../src/plugin/permission/store.permission.ts | 89 +++ .../plugin/permission/use-crud-permission.ts | 60 ++ .../src/plugin/permission/util.permission.ts | 29 + packages/ui/certd-client/src/router/index.ts | 68 ++ .../ui/certd-client/src/router/resolve.ts | 155 +++++ .../src/router/source/framework.ts | 31 + .../certd-client/src/router/source/header.ts | 73 ++ .../src/router/source/modules/crud.ts | 635 ++++++++++++++++++ .../src/router/source/modules/sys.ts | 61 ++ .../certd-client/src/router/source/outside.ts | 22 + packages/ui/certd-client/src/shims-vue.d.ts | 5 + packages/ui/certd-client/src/store/index.ts | 9 + .../ui/certd-client/src/store/modules/page.ts | 436 ++++++++++++ .../src/store/modules/resource.ts | 127 ++++ .../src/store/modules/settings.ts | 63 ++ .../ui/certd-client/src/store/modules/user.ts | 106 +++ packages/ui/certd-client/src/style.css | 1 + .../ui/certd-client/src/style/common.less | 44 ++ .../certd-client/src/style/fix-windicss.less | 3 + .../ui/certd-client/src/style/scroll.less | 28 + .../certd-client/src/style/theme/default.less | 27 + .../certd-client/src/style/theme/index.less | 4 + .../ui/certd-client/src/style/transition.less | 36 + .../ui/certd-client/src/types/global.d.ts | 99 +++ packages/ui/certd-client/src/utils/index.ts | 12 + .../ui/certd-client/src/utils/util.common.ts | 33 + .../ui/certd-client/src/utils/util.env.ts | 40 ++ .../ui/certd-client/src/utils/util.mitt.ts | 2 + .../ui/certd-client/src/utils/util.site.ts | 11 + .../ui/certd-client/src/utils/util.storage.ts | 113 ++++ .../src/views/crud/advanced/big-data/api.js | 42 ++ .../src/views/crud/advanced/big-data/crud.jsx | 170 +++++ .../views/crud/advanced/big-data/index.vue | 43 ++ .../src/views/crud/advanced/big-data/mock.js | 126 ++++ .../views/crud/advanced/from-backend/api.js | 48 ++ .../advanced/from-backend/crud-backend.js | 29 + .../views/crud/advanced/from-backend/crud.jsx | 27 + .../crud/advanced/from-backend/index.vue | 45 ++ .../views/crud/advanced/from-backend/mock.js | 35 + .../views/crud/advanced/in-dialog/crud/api.js | 42 ++ .../crud/advanced/in-dialog/crud/crud.jsx | 106 +++ .../crud/advanced/in-dialog/crud/index.vue | 40 ++ .../crud/advanced/in-dialog/crud/mock.js | 40 ++ .../views/crud/advanced/in-dialog/index.vue | 37 + .../src/views/crud/advanced/linkage/api.js | 42 ++ .../src/views/crud/advanced/linkage/crud.jsx | 118 ++++ .../src/views/crud/advanced/linkage/index.vue | 38 ++ .../src/views/crud/advanced/linkage/mock.js | 129 ++++ .../crud/advanced/local-pagination/api.js | 42 ++ .../crud/advanced/local-pagination/crud.jsx | 101 +++ .../crud/advanced/local-pagination/index.vue | 57 ++ .../crud/advanced/local-pagination/mock.js | 19 + .../src/views/crud/advanced/nest/api.js | 50 ++ .../crud/advanced/nest/aside-table/api.js | 50 ++ .../crud/advanced/nest/aside-table/crud.jsx | 56 ++ .../crud/advanced/nest/aside-table/index.vue | 43 ++ .../crud/advanced/nest/aside-table/mock.js | 26 + .../src/views/crud/advanced/nest/crud.jsx | 101 +++ .../src/views/crud/advanced/nest/index.vue | 59 ++ .../src/views/crud/advanced/nest/mock.js | 22 + .../views/crud/advanced/nest/sub-table/api.js | 50 ++ .../crud/advanced/nest/sub-table/crud.jsx | 62 ++ .../crud/advanced/nest/sub-table/index.vue | 61 ++ .../crud/advanced/nest/sub-table/mock.js | 19 + .../crud/basis/column-merge-plugin/api.js | 42 ++ .../crud/basis/column-merge-plugin/crud.jsx | 69 ++ .../crud/basis/column-merge-plugin/index.vue | 34 + .../crud/basis/column-merge-plugin/mock.js | 25 + .../src/views/crud/basis/columns-set/api.js | 50 ++ .../src/views/crud/basis/columns-set/crud.jsx | 69 ++ .../views/crud/basis/columns-set/index.vue | 52 ++ .../src/views/crud/basis/columns-set/mock.js | 19 + .../src/views/crud/basis/compute-more/api.js | 42 ++ .../views/crud/basis/compute-more/crud.jsx | 79 +++ .../views/crud/basis/compute-more/index.vue | 43 ++ .../src/views/crud/basis/compute-more/mock.js | 32 + .../src/views/crud/basis/compute/api.js | 42 ++ .../src/views/crud/basis/compute/crud.jsx | 211 ++++++ .../src/views/crud/basis/compute/index.vue | 60 ++ .../src/views/crud/basis/compute/mock.js | 34 + .../src/views/crud/basis/first/index.vue | 109 +++ .../src/views/crud/basis/i18n/api.js | 42 ++ .../src/views/crud/basis/i18n/crud.jsx | 72 ++ .../src/views/crud/basis/i18n/index.vue | 53 ++ .../src/views/crud/basis/i18n/mock.js | 25 + .../src/views/crud/basis/layout-card/api.js | 42 ++ .../src/views/crud/basis/layout-card/crud.jsx | 73 ++ .../views/crud/basis/layout-card/index.vue | 46 ++ .../src/views/crud/basis/layout-card/mock.js | 25 + .../src/views/crud/basis/layout-custom/api.js | 42 ++ .../views/crud/basis/layout-custom/crud.jsx | 75 +++ .../basis/layout-custom/custom-layout.vue | 74 ++ .../views/crud/basis/layout-custom/index.vue | 56 ++ .../views/crud/basis/layout-custom/mock.js | 25 + .../src/views/crud/basis/value-change/api.js | 42 ++ .../views/crud/basis/value-change/crud.jsx | 95 +++ .../views/crud/basis/value-change/index.vue | 43 ++ .../src/views/crud/basis/value-change/mock.js | 32 + .../src/views/crud/component/button/api.js | 42 ++ .../src/views/crud/component/button/crud.jsx | 115 ++++ .../src/views/crud/component/button/index.vue | 42 ++ .../src/views/crud/component/button/mock.js | 23 + .../src/views/crud/component/cascader/api.js | 42 ++ .../views/crud/component/cascader/crud.jsx | 137 ++++ .../views/crud/component/cascader/index.vue | 40 ++ .../src/views/crud/component/cascader/mock.js | 23 + .../src/views/crud/component/checkbox/api.js | 42 ++ .../views/crud/component/checkbox/crud.jsx | 50 ++ .../views/crud/component/checkbox/index.vue | 40 ++ .../src/views/crud/component/checkbox/mock.js | 19 + .../src/views/crud/component/date/api.js | 42 ++ .../src/views/crud/component/date/crud.jsx | 174 +++++ .../src/views/crud/component/date/index.vue | 47 ++ .../src/views/crud/component/date/mock.js | 44 ++ .../src/views/crud/component/editor/api.js | 42 ++ .../src/views/crud/component/editor/crud.jsx | 107 +++ .../src/views/crud/component/editor/index.vue | 44 ++ .../src/views/crud/component/editor/mock.js | 29 + .../src/views/crud/component/icon/api.js | 42 ++ .../src/views/crud/component/icon/crud.jsx | 75 +++ .../src/views/crud/component/icon/index.vue | 42 ++ .../src/views/crud/component/icon/mock.js | 22 + .../src/views/crud/component/json/api.js | 42 ++ .../src/views/crud/component/json/crud.jsx | 78 +++ .../src/views/crud/component/json/index.vue | 40 ++ .../src/views/crud/component/json/mock.js | 18 + .../src/views/crud/component/number/api.js | 42 ++ .../src/views/crud/component/number/crud.jsx | 71 ++ .../src/views/crud/component/number/index.vue | 40 ++ .../src/views/crud/component/number/mock.js | 25 + .../src/views/crud/component/radio/api.js | 42 ++ .../src/views/crud/component/radio/crud.jsx | 73 ++ .../src/views/crud/component/radio/index.vue | 42 ++ .../src/views/crud/component/radio/mock.js | 24 + .../src/views/crud/component/select/api.js | 42 ++ .../src/views/crud/component/select/crud.jsx | 311 +++++++++ .../src/views/crud/component/select/index.vue | 45 ++ .../src/views/crud/component/select/mock.js | 42 ++ .../src/views/crud/component/switch/api.js | 42 ++ .../src/views/crud/component/switch/crud.jsx | 141 ++++ .../src/views/crud/component/switch/index.vue | 40 ++ .../src/views/crud/component/switch/mock.js | 27 + .../src/views/crud/component/text/api.js | 42 ++ .../src/views/crud/component/text/crud.jsx | 130 ++++ .../src/views/crud/component/text/index.vue | 40 ++ .../src/views/crud/component/text/mock.js | 43 ++ .../src/views/crud/component/tree/api.js | 42 ++ .../src/views/crud/component/tree/crud.jsx | 81 +++ .../src/views/crud/component/tree/index.vue | 40 ++ .../src/views/crud/component/tree/mock.js | 16 + .../crud/component/uploader/alioss/api.js | 42 ++ .../crud/component/uploader/alioss/crud.jsx | 75 +++ .../crud/component/uploader/alioss/index.vue | 40 ++ .../crud/component/uploader/alioss/mock.js | 24 + .../views/crud/component/uploader/cos/api.js | 42 ++ .../crud/component/uploader/cos/crud.jsx | 75 +++ .../crud/component/uploader/cos/index.vue | 40 ++ .../views/crud/component/uploader/cos/mock.js | 22 + .../crud/component/uploader/cropper/api.js | 42 ++ .../crud/component/uploader/cropper/crud.jsx | 110 +++ .../crud/component/uploader/cropper/index.vue | 40 ++ .../crud/component/uploader/cropper/mock.js | 24 + .../views/crud/component/uploader/form/api.js | 42 ++ .../crud/component/uploader/form/crud.jsx | 223 ++++++ .../crud/component/uploader/form/index.vue | 43 ++ .../crud/component/uploader/form/mock.js | 24 + .../crud/component/uploader/qiniu/api.js | 42 ++ .../crud/component/uploader/qiniu/crud.jsx | 73 ++ .../crud/component/uploader/qiniu/index.vue | 40 ++ .../crud/component/uploader/qiniu/mock.js | 22 + .../src/views/crud/debug/select/api.js | 42 ++ .../src/views/crud/debug/select/crud.jsx | 106 +++ .../src/views/crud/debug/select/index.vue | 40 ++ .../src/views/crud/debug/select/mock.js | 9 + .../src/views/crud/dict/cloneable/api.js | 42 ++ .../src/views/crud/dict/cloneable/crud.jsx | 88 +++ .../src/views/crud/dict/cloneable/index.vue | 48 ++ .../src/views/crud/dict/cloneable/mock.js | 21 + .../src/views/crud/dict/prototype/api.js | 42 ++ .../src/views/crud/dict/prototype/crud.jsx | 128 ++++ .../src/views/crud/dict/prototype/index.vue | 48 ++ .../src/views/crud/dict/prototype/mock.js | 31 + .../src/views/crud/dict/shared/manager/api.js | 42 ++ .../views/crud/dict/shared/manager/crud.tsx | 58 ++ .../views/crud/dict/shared/manager/index.vue | 33 + .../views/crud/dict/shared/manager/mock.js | 23 + .../src/views/crud/dict/shared/shared-dict.ts | 10 + .../src/views/crud/dict/shared/use/api.js | 42 ++ .../src/views/crud/dict/shared/use/crud.jsx | 47 ++ .../src/views/crud/dict/shared/use/index.vue | 33 + .../src/views/crud/dict/shared/use/mock.js | 19 + .../src/views/crud/dict/single/api.js | 42 ++ .../src/views/crud/dict/single/crud.jsx | 111 +++ .../src/views/crud/dict/single/index.vue | 49 ++ .../src/views/crud/dict/single/mock.js | 21 + .../views/crud/feature/column-resize/api.js | 42 ++ .../views/crud/feature/column-resize/crud.jsx | 70 ++ .../crud/feature/column-resize/index.vue | 43 ++ .../views/crud/feature/column-resize/mock.js | 20 + .../src/views/crud/feature/column-sort/api.js | 50 ++ .../views/crud/feature/column-sort/crud.jsx | 94 +++ .../views/crud/feature/column-sort/index.vue | 47 ++ .../views/crud/feature/column-sort/mock.js | 31 + .../src/views/crud/feature/columns-set/api.js | 50 ++ .../views/crud/feature/columns-set/crud.jsx | 55 ++ .../views/crud/feature/columns-set/index.vue | 49 ++ .../views/crud/feature/columns-set/mock.js | 19 + .../views/crud/feature/editable-row/api.js | 50 ++ .../views/crud/feature/editable-row/crud.jsx | 88 +++ .../views/crud/feature/editable-row/index.vue | 40 ++ .../views/crud/feature/editable-row/mock.js | 19 + .../src/views/crud/feature/editable/api.js | 50 ++ .../src/views/crud/feature/editable/crud.jsx | 105 +++ .../src/views/crud/feature/editable/index.vue | 100 +++ .../src/views/crud/feature/editable/mock.js | 19 + .../src/views/crud/feature/expand/api.js | 50 ++ .../src/views/crud/feature/expand/crud.jsx | 63 ++ .../src/views/crud/feature/expand/index.vue | 65 ++ .../src/views/crud/feature/expand/mock.js | 19 + .../src/views/crud/feature/filter/api.js | 42 ++ .../src/views/crud/feature/filter/crud.jsx | 70 ++ .../src/views/crud/feature/filter/index.vue | 40 ++ .../src/views/crud/feature/filter/mock.js | 19 + .../src/views/crud/feature/fixed/api.js | 50 ++ .../src/views/crud/feature/fixed/crud.jsx | 90 +++ .../src/views/crud/feature/fixed/index.vue | 39 ++ .../src/views/crud/feature/fixed/mock.js | 14 + .../views/crud/feature/header-group/api.js | 42 ++ .../views/crud/feature/header-group/crud.jsx | 109 +++ .../views/crud/feature/header-group/index.vue | 42 ++ .../views/crud/feature/header-group/mock.js | 30 + .../src/views/crud/feature/height/api.js | 42 ++ .../src/views/crud/feature/height/crud.jsx | 57 ++ .../src/views/crud/feature/height/index.vue | 42 ++ .../src/views/crud/feature/height/mock.js | 24 + .../src/views/crud/feature/hide/api.js | 42 ++ .../src/views/crud/feature/hide/crud.jsx | 100 +++ .../src/views/crud/feature/hide/index.vue | 184 +++++ .../src/views/crud/feature/hide/mock.js | 19 + .../src/views/crud/feature/index/api.js | 50 ++ .../src/views/crud/feature/index/crud.jsx | 56 ++ .../src/views/crud/feature/index/index.vue | 39 ++ .../src/views/crud/feature/index/mock.js | 19 + .../views/crud/feature/local-v-model/crud.jsx | 32 + .../crud/feature/local-v-model/index.vue | 51 ++ .../crud/feature/local-v-model/local.vue | 67 ++ .../src/views/crud/feature/local/crud.jsx | 35 + .../src/views/crud/feature/local/index.vue | 89 +++ .../src/views/crud/feature/merge/api.js | 43 ++ .../src/views/crud/feature/merge/crud.jsx | 129 ++++ .../src/views/crud/feature/merge/index.vue | 39 ++ .../src/views/crud/feature/merge/mock.js | 36 + .../src/views/crud/feature/remove/api.js | 42 ++ .../src/views/crud/feature/remove/crud.jsx | 74 ++ .../src/views/crud/feature/remove/index.vue | 40 ++ .../src/views/crud/feature/remove/mock.js | 25 + .../views/crud/feature/search-multi/api.js | 42 ++ .../views/crud/feature/search-multi/crud.jsx | 143 ++++ .../views/crud/feature/search-multi/index.vue | 41 ++ .../views/crud/feature/search-multi/mock.js | 19 + .../src/views/crud/feature/search/api.js | 42 ++ .../src/views/crud/feature/search/crud.jsx | 91 +++ .../src/views/crud/feature/search/index.vue | 57 ++ .../src/views/crud/feature/search/mock.js | 19 + .../views/crud/feature/selection-radio/api.js | 50 ++ .../crud/feature/selection-radio/crud.jsx | 67 ++ .../crud/feature/selection-radio/index.vue | 45 ++ .../crud/feature/selection-radio/mock.js | 19 + .../src/views/crud/feature/selection/api.js | 50 ++ .../src/views/crud/feature/selection/crud.jsx | 67 ++ .../views/crud/feature/selection/index.vue | 68 ++ .../src/views/crud/feature/selection/mock.js | 19 + .../src/views/crud/feature/sortable/api.js | 50 ++ .../src/views/crud/feature/sortable/crud.jsx | 62 ++ .../src/views/crud/feature/sortable/index.vue | 39 ++ .../src/views/crud/feature/sortable/mock.js | 25 + .../src/views/crud/feature/tree/api.js | 50 ++ .../src/views/crud/feature/tree/crud.jsx | 91 +++ .../src/views/crud/feature/tree/index.vue | 65 ++ .../src/views/crud/feature/tree/mock.js | 85 +++ .../views/crud/feature/value-builder/api.js | 50 ++ .../views/crud/feature/value-builder/crud.jsx | 54 ++ .../crud/feature/value-builder/index.vue | 46 ++ .../views/crud/feature/value-builder/mock.js | 21 + .../src/views/crud/form/base/api.js | 42 ++ .../src/views/crud/form/base/crud.jsx | 55 ++ .../src/views/crud/form/base/index.vue | 31 + .../src/views/crud/form/base/mock.js | 310 +++++++++ .../src/views/crud/form/custom-form/api.js | 42 ++ .../src/views/crud/form/custom-form/crud.jsx | 40 ++ .../src/views/crud/form/custom-form/index.vue | 86 +++ .../src/views/crud/form/custom-form/mock.js | 303 +++++++++ .../src/views/crud/form/drawer/api.js | 42 ++ .../src/views/crud/form/drawer/crud.jsx | 44 ++ .../src/views/crud/form/drawer/index.vue | 40 ++ .../src/views/crud/form/drawer/mock.js | 40 ++ .../src/views/crud/form/group-tabs/api.js | 42 ++ .../src/views/crud/form/group-tabs/crud.jsx | 114 ++++ .../src/views/crud/form/group-tabs/index.vue | 40 ++ .../src/views/crud/form/group-tabs/mock.js | 303 +++++++++ .../src/views/crud/form/group/api.js | 42 ++ .../src/views/crud/form/group/crud.jsx | 143 ++++ .../src/views/crud/form/group/index.vue | 46 ++ .../src/views/crud/form/group/mock.js | 303 +++++++++ .../src/views/crud/form/helper/api.js | 42 ++ .../src/views/crud/form/helper/crud.jsx | 72 ++ .../src/views/crud/form/helper/index.vue | 48 ++ .../src/views/crud/form/helper/mock.js | 310 +++++++++ .../src/views/crud/form/independent/crud.jsx | 59 ++ .../src/views/crud/form/independent/index.vue | 215 ++++++ .../src/views/crud/form/inner/api.js | 42 ++ .../src/views/crud/form/inner/area/api.js | 50 ++ .../src/views/crud/form/inner/area/crud.jsx | 39 ++ .../src/views/crud/form/inner/area/index.vue | 40 ++ .../src/views/crud/form/inner/area/mock.js | 24 + .../src/views/crud/form/inner/crud.jsx | 77 +++ .../src/views/crud/form/inner/index.vue | 40 ++ .../src/views/crud/form/inner/mock.js | 25 + .../src/views/crud/form/layout-flex/api.js | 42 ++ .../src/views/crud/form/layout-flex/crud.jsx | 63 ++ .../src/views/crud/form/layout-flex/index.vue | 43 ++ .../src/views/crud/form/layout-flex/mock.js | 35 + .../src/views/crud/form/layout-grid/api.js | 42 ++ .../src/views/crud/form/layout-grid/crud.jsx | 67 ++ .../src/views/crud/form/layout-grid/index.vue | 52 ++ .../src/views/crud/form/layout-grid/mock.js | 34 + .../src/views/crud/form/layout/api.js | 42 ++ .../src/views/crud/form/layout/crud.jsx | 101 +++ .../src/views/crud/form/layout/index.vue | 50 ++ .../src/views/crud/form/layout/mock.js | 41 ++ .../src/views/crud/form/nest/api.js | 42 ++ .../src/views/crud/form/nest/crud.jsx | 76 +++ .../src/views/crud/form/nest/index.vue | 48 ++ .../src/views/crud/form/nest/mock.js | 319 +++++++++ .../src/views/crud/form/new-page/api.js | 42 ++ .../src/views/crud/form/new-page/crud.jsx | 96 +++ .../src/views/crud/form/new-page/edit.vue | 81 +++ .../src/views/crud/form/new-page/index.vue | 43 ++ .../src/views/crud/form/new-page/mock.js | 22 + .../src/views/crud/form/reset/api.js | 42 ++ .../src/views/crud/form/reset/crud.jsx | 56 ++ .../src/views/crud/form/reset/index.vue | 40 ++ .../src/views/crud/form/reset/mock.js | 40 ++ .../src/views/crud/form/single-column/api.js | 42 ++ .../views/crud/form/single-column/crud.jsx | 59 ++ .../views/crud/form/single-column/index.vue | 31 + .../src/views/crud/form/single-column/mock.js | 310 +++++++++ .../src/views/crud/form/validation/api.js | 42 ++ .../src/views/crud/form/validation/crud.jsx | 135 ++++ .../src/views/crud/form/validation/index.vue | 40 ++ .../src/views/crud/form/validation/mock.js | 310 +++++++++ .../src/views/crud/home/index.vue | 15 + .../src/views/crud/home/page-cover/helper.js | 31 + .../views/crud/home/page-cover/image/crud.png | Bin 0 -> 202647 bytes .../home/page-cover/image/darkblue@2x.png | Bin 0 -> 9259 bytes .../views/crud/home/page-cover/image/logo.svg | 178 +++++ .../src/views/crud/home/page-cover/index.vue | 139 ++++ .../src/views/crud/row-handle/dropdown/api.js | 42 ++ .../views/crud/row-handle/dropdown/crud.jsx | 82 +++ .../views/crud/row-handle/dropdown/index.vue | 40 ++ .../views/crud/row-handle/dropdown/mock.js | 19 + .../src/views/crud/row-handle/tooltip/api.js | 50 ++ .../views/crud/row-handle/tooltip/crud.jsx | 84 +++ .../views/crud/row-handle/tooltip/index.vue | 51 ++ .../src/views/crud/row-handle/tooltip/mock.js | 19 + .../src/views/crud/slots/cell/api.js | 42 ++ .../src/views/crud/slots/cell/crud.jsx | 89 +++ .../src/views/crud/slots/cell/index.vue | 79 +++ .../src/views/crud/slots/cell/mock.js | 26 + .../src/views/crud/slots/form-item/api.js | 42 ++ .../src/views/crud/slots/form-item/crud.jsx | 51 ++ .../src/views/crud/slots/form-item/index.vue | 72 ++ .../src/views/crud/slots/form-item/mock.js | 13 + .../src/views/crud/slots/form/api.js | 42 ++ .../src/views/crud/slots/form/crud.jsx | 50 ++ .../src/views/crud/slots/form/index.vue | 69 ++ .../src/views/crud/slots/form/mock.js | 13 + .../src/views/crud/slots/layout/api.js | 42 ++ .../src/views/crud/slots/layout/crud.jsx | 49 ++ .../src/views/crud/slots/layout/index.vue | 77 +++ .../src/views/crud/slots/layout/mock.js | 19 + .../src/views/crud/slots/search/api.js | 42 ++ .../src/views/crud/slots/search/crud.jsx | 49 ++ .../src/views/crud/slots/search/index.vue | 54 ++ .../src/views/crud/slots/search/mock.js | 19 + .../src/views/framework/error/404.vue | 18 + .../src/views/framework/home/index.vue | 15 + .../views/framework/home/page-cover/helper.js | 31 + .../framework/home/page-cover/image/crud.png | Bin 0 -> 202647 bytes .../home/page-cover/image/darkblue@2x.png | Bin 0 -> 9259 bytes .../framework/home/page-cover/image/logo.svg | 178 +++++ .../views/framework/home/page-cover/index.vue | 139 ++++ .../src/views/framework/login/index.vue | 270 ++++++++ .../src/views/framework/register/index.vue | 178 +++++ .../src/views/sys/authority/permission/api.js | 48 ++ .../views/sys/authority/permission/crud.jsx | 150 +++++ .../permission/fs-permission-tree.vue | 178 +++++ .../views/sys/authority/permission/index.vue | 90 +++ .../src/views/sys/authority/role/api.js | 70 ++ .../src/views/sys/authority/role/crud.jsx | 81 +++ .../src/views/sys/authority/role/index.vue | 133 ++++ .../src/views/sys/authority/user/api.js | 41 ++ .../src/views/sys/authority/user/crud.jsx | 146 ++++ .../src/views/sys/authority/user/index.vue | 45 ++ packages/ui/certd-client/tailwind.config.js | 11 + .../certd-client/tests/unit/example.spec.ts | 13 + packages/ui/certd-client/tsconfig.json | 46 ++ packages/ui/certd-client/vite.config.ts | 101 +++ packages/ui/certd-client/windi.config.js | 6 + 567 files changed, 36438 insertions(+), 2 deletions(-) create mode 100644 packages/ui/certd-client/.browserslistrc create mode 100644 packages/ui/certd-client/.env create mode 100644 packages/ui/certd-client/.env.debug create mode 100644 packages/ui/certd-client/.env.debugpm create mode 100644 packages/ui/certd-client/.env.pm create mode 100644 packages/ui/certd-client/.env.production create mode 100644 packages/ui/certd-client/.eslintignore create mode 100644 packages/ui/certd-client/.eslintrc.js create mode 100644 packages/ui/certd-client/.gitignore create mode 100644 packages/ui/certd-client/.npmignore create mode 100644 packages/ui/certd-client/.prettierrc create mode 100644 packages/ui/certd-client/CHANGELOG.md create mode 100644 packages/ui/certd-client/LICENSE create mode 100644 packages/ui/certd-client/README.md create mode 100644 packages/ui/certd-client/build/modify-vars.ts create mode 100644 packages/ui/certd-client/build/theme-colors.ts create mode 100644 packages/ui/certd-client/build/theme-plugin.ts create mode 100644 packages/ui/certd-client/index.html create mode 100644 packages/ui/certd-client/package.json create mode 100644 packages/ui/certd-client/public/favicon.ico create mode 100644 packages/ui/certd-client/public/images/logo-certd/logo.svg create mode 100644 packages/ui/certd-client/public/images/logo-certd/rect-black.svg create mode 100644 packages/ui/certd-client/public/images/logo-certd/rect.svg create mode 100644 packages/ui/certd-client/public/images/logo-certd/square.svg create mode 100644 packages/ui/certd-client/public/images/logo/logo.svg create mode 100644 packages/ui/certd-client/public/images/logo/rect-black.svg create mode 100644 packages/ui/certd-client/public/images/logo/rect.svg create mode 100644 packages/ui/certd-client/public/images/logo/square.svg create mode 100644 packages/ui/certd-client/public/index.css create mode 100644 packages/ui/certd-client/public/index.html create mode 100644 packages/ui/certd-client/public/logo.svg create mode 100644 packages/ui/certd-client/src/App.vue create mode 100644 packages/ui/certd-client/src/api/modules/api.user.mock.ts create mode 100644 packages/ui/certd-client/src/api/modules/api.user.ts create mode 100644 packages/ui/certd-client/src/api/service.ts create mode 100644 packages/ui/certd-client/src/api/tools.ts create mode 100644 packages/ui/certd-client/src/assets/background.svg create mode 100644 packages/ui/certd-client/src/assets/logo.png create mode 100644 packages/ui/certd-client/src/components/highlight-styles/agate.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/androidstudio.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/arduino-light.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/arta.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/ascetic.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atelier-cave-dark.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atelier-cave-light.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atelier-dune-dark.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atelier-dune-light.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atelier-estuary-dark.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atelier-estuary-light.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atelier-forest-dark.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atelier-forest-light.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atelier-heath-dark.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atelier-heath-light.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atelier-lakeside-dark.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atelier-lakeside-light.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atelier-plateau-dark.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atelier-plateau-light.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atelier-savanna-dark.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atelier-savanna-light.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atelier-seaside-dark.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atelier-seaside-light.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atelier-sulphurpool-dark.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atelier-sulphurpool-light.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atom-one-dark.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/atom-one-light.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/brown-paper.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/brown-papersq.png create mode 100644 packages/ui/certd-client/src/components/highlight-styles/codepen-embed.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/color-brewer.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/darcula.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/dark.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/darkula.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/default.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/docco.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/dracula.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/far.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/foundation.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/github-gist.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/github.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/googlecode.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/grayscale.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/gruvbox-dark.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/gruvbox-light.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/hopscotch.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/hybrid.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/idea.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/ir-black.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/kimbie.dark.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/kimbie.light.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/magula.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/mono-blue.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/monokai-sublime.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/monokai.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/obsidian.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/ocean.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/paraiso-dark.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/paraiso-light.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/pojoaque.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/pojoaque.jpg create mode 100644 packages/ui/certd-client/src/components/highlight-styles/purebasic.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/qtcreator_dark.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/qtcreator_light.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/railscasts.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/rainbow.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/routeros.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/school-book.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/school-book.png create mode 100644 packages/ui/certd-client/src/components/highlight-styles/solarized-dark.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/solarized-light.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/sunburst.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/tomorrow-night-blue.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/tomorrow-night-bright.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/tomorrow-night-eighties.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/tomorrow-night.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/tomorrow.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/vs.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/vs2015.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/xcode.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/xt256.css create mode 100644 packages/ui/certd-client/src/components/highlight-styles/zenburn.css create mode 100644 packages/ui/certd-client/src/components/highlight/index.vue create mode 100644 packages/ui/certd-client/src/components/highlight/libs/htmlFormat.js create mode 100644 packages/ui/certd-client/src/components/index.ts create mode 100644 packages/ui/certd-client/src/i18n/index.ts create mode 100644 packages/ui/certd-client/src/i18n/locale/en.ts create mode 100644 packages/ui/certd-client/src/i18n/locale/zh_CN.ts create mode 100644 packages/ui/certd-client/src/layout/components/contextmenu/components/contentmenuList/index.vue create mode 100644 packages/ui/certd-client/src/layout/components/contextmenu/index.vue create mode 100644 packages/ui/certd-client/src/layout/components/locale/index.vue create mode 100644 packages/ui/certd-client/src/layout/components/menu/index.jsx create mode 100644 packages/ui/certd-client/src/layout/components/menu/index.less create mode 100644 packages/ui/certd-client/src/layout/components/source-link/index.vue create mode 100644 packages/ui/certd-client/src/layout/components/tabs/index.vue create mode 100644 packages/ui/certd-client/src/layout/components/theme/color-picker.vue create mode 100644 packages/ui/certd-client/src/layout/components/theme/index.vue create mode 100644 packages/ui/certd-client/src/layout/components/user-info/index.vue create mode 100644 packages/ui/certd-client/src/layout/layout-framework.vue create mode 100644 packages/ui/certd-client/src/layout/layout-outside.vue create mode 100644 packages/ui/certd-client/src/layout/layout-pass.vue create mode 100644 packages/ui/certd-client/src/main.ts create mode 100644 packages/ui/certd-client/src/mock/base.js create mode 100644 packages/ui/certd-client/src/mock/common/cascader-data.js create mode 100644 packages/ui/certd-client/src/mock/common/mock.dict.js create mode 100644 packages/ui/certd-client/src/mock/common/pca-data-little.js create mode 100644 packages/ui/certd-client/src/mock/common/pcas-data.js create mode 100644 packages/ui/certd-client/src/mock/index.js create mode 100644 packages/ui/certd-client/src/plugin/fast-crud/index.tsx create mode 100644 packages/ui/certd-client/src/plugin/iconfont/iconfont.js create mode 100644 packages/ui/certd-client/src/plugin/iconfont/index.ts create mode 100644 packages/ui/certd-client/src/plugin/iconify/index.ts create mode 100644 packages/ui/certd-client/src/plugin/index.ts create mode 100644 packages/ui/certd-client/src/plugin/permission/api.ts create mode 100644 packages/ui/certd-client/src/plugin/permission/directive/index.js create mode 100644 packages/ui/certd-client/src/plugin/permission/directive/permission.js create mode 100644 packages/ui/certd-client/src/plugin/permission/errors.ts create mode 100644 packages/ui/certd-client/src/plugin/permission/hook.ts create mode 100644 packages/ui/certd-client/src/plugin/permission/index.ts create mode 100644 packages/ui/certd-client/src/plugin/permission/store.permission.ts create mode 100644 packages/ui/certd-client/src/plugin/permission/use-crud-permission.ts create mode 100644 packages/ui/certd-client/src/plugin/permission/util.permission.ts create mode 100644 packages/ui/certd-client/src/router/index.ts create mode 100644 packages/ui/certd-client/src/router/resolve.ts create mode 100644 packages/ui/certd-client/src/router/source/framework.ts create mode 100644 packages/ui/certd-client/src/router/source/header.ts create mode 100644 packages/ui/certd-client/src/router/source/modules/crud.ts create mode 100644 packages/ui/certd-client/src/router/source/modules/sys.ts create mode 100644 packages/ui/certd-client/src/router/source/outside.ts create mode 100644 packages/ui/certd-client/src/shims-vue.d.ts create mode 100644 packages/ui/certd-client/src/store/index.ts create mode 100644 packages/ui/certd-client/src/store/modules/page.ts create mode 100644 packages/ui/certd-client/src/store/modules/resource.ts create mode 100644 packages/ui/certd-client/src/store/modules/settings.ts create mode 100644 packages/ui/certd-client/src/store/modules/user.ts create mode 100644 packages/ui/certd-client/src/style.css create mode 100644 packages/ui/certd-client/src/style/common.less create mode 100644 packages/ui/certd-client/src/style/fix-windicss.less create mode 100644 packages/ui/certd-client/src/style/scroll.less create mode 100644 packages/ui/certd-client/src/style/theme/default.less create mode 100644 packages/ui/certd-client/src/style/theme/index.less create mode 100644 packages/ui/certd-client/src/style/transition.less create mode 100644 packages/ui/certd-client/src/types/global.d.ts create mode 100644 packages/ui/certd-client/src/utils/index.ts create mode 100644 packages/ui/certd-client/src/utils/util.common.ts create mode 100644 packages/ui/certd-client/src/utils/util.env.ts create mode 100644 packages/ui/certd-client/src/utils/util.mitt.ts create mode 100644 packages/ui/certd-client/src/utils/util.site.ts create mode 100644 packages/ui/certd-client/src/utils/util.storage.ts create mode 100644 packages/ui/certd-client/src/views/crud/advanced/big-data/api.js create mode 100644 packages/ui/certd-client/src/views/crud/advanced/big-data/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/advanced/big-data/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/advanced/big-data/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/advanced/from-backend/api.js create mode 100644 packages/ui/certd-client/src/views/crud/advanced/from-backend/crud-backend.js create mode 100644 packages/ui/certd-client/src/views/crud/advanced/from-backend/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/advanced/from-backend/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/advanced/from-backend/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/advanced/in-dialog/crud/api.js create mode 100644 packages/ui/certd-client/src/views/crud/advanced/in-dialog/crud/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/advanced/in-dialog/crud/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/advanced/in-dialog/crud/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/advanced/in-dialog/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/advanced/linkage/api.js create mode 100644 packages/ui/certd-client/src/views/crud/advanced/linkage/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/advanced/linkage/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/advanced/linkage/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/advanced/local-pagination/api.js create mode 100644 packages/ui/certd-client/src/views/crud/advanced/local-pagination/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/advanced/local-pagination/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/advanced/local-pagination/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/advanced/nest/api.js create mode 100644 packages/ui/certd-client/src/views/crud/advanced/nest/aside-table/api.js create mode 100644 packages/ui/certd-client/src/views/crud/advanced/nest/aside-table/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/advanced/nest/aside-table/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/advanced/nest/aside-table/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/advanced/nest/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/advanced/nest/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/advanced/nest/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/advanced/nest/sub-table/api.js create mode 100644 packages/ui/certd-client/src/views/crud/advanced/nest/sub-table/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/advanced/nest/sub-table/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/advanced/nest/sub-table/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/basis/column-merge-plugin/api.js create mode 100644 packages/ui/certd-client/src/views/crud/basis/column-merge-plugin/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/basis/column-merge-plugin/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/basis/column-merge-plugin/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/basis/columns-set/api.js create mode 100644 packages/ui/certd-client/src/views/crud/basis/columns-set/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/basis/columns-set/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/basis/columns-set/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/basis/compute-more/api.js create mode 100644 packages/ui/certd-client/src/views/crud/basis/compute-more/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/basis/compute-more/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/basis/compute-more/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/basis/compute/api.js create mode 100644 packages/ui/certd-client/src/views/crud/basis/compute/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/basis/compute/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/basis/compute/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/basis/first/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/basis/i18n/api.js create mode 100644 packages/ui/certd-client/src/views/crud/basis/i18n/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/basis/i18n/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/basis/i18n/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/basis/layout-card/api.js create mode 100644 packages/ui/certd-client/src/views/crud/basis/layout-card/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/basis/layout-card/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/basis/layout-card/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/basis/layout-custom/api.js create mode 100644 packages/ui/certd-client/src/views/crud/basis/layout-custom/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/basis/layout-custom/custom-layout.vue create mode 100644 packages/ui/certd-client/src/views/crud/basis/layout-custom/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/basis/layout-custom/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/basis/value-change/api.js create mode 100644 packages/ui/certd-client/src/views/crud/basis/value-change/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/basis/value-change/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/basis/value-change/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/component/button/api.js create mode 100644 packages/ui/certd-client/src/views/crud/component/button/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/component/button/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/component/button/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/component/cascader/api.js create mode 100644 packages/ui/certd-client/src/views/crud/component/cascader/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/component/cascader/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/component/cascader/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/component/checkbox/api.js create mode 100644 packages/ui/certd-client/src/views/crud/component/checkbox/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/component/checkbox/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/component/checkbox/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/component/date/api.js create mode 100644 packages/ui/certd-client/src/views/crud/component/date/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/component/date/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/component/date/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/component/editor/api.js create mode 100644 packages/ui/certd-client/src/views/crud/component/editor/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/component/editor/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/component/editor/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/component/icon/api.js create mode 100644 packages/ui/certd-client/src/views/crud/component/icon/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/component/icon/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/component/icon/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/component/json/api.js create mode 100644 packages/ui/certd-client/src/views/crud/component/json/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/component/json/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/component/json/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/component/number/api.js create mode 100644 packages/ui/certd-client/src/views/crud/component/number/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/component/number/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/component/number/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/component/radio/api.js create mode 100644 packages/ui/certd-client/src/views/crud/component/radio/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/component/radio/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/component/radio/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/component/select/api.js create mode 100644 packages/ui/certd-client/src/views/crud/component/select/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/component/select/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/component/select/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/component/switch/api.js create mode 100644 packages/ui/certd-client/src/views/crud/component/switch/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/component/switch/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/component/switch/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/component/text/api.js create mode 100644 packages/ui/certd-client/src/views/crud/component/text/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/component/text/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/component/text/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/component/tree/api.js create mode 100644 packages/ui/certd-client/src/views/crud/component/tree/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/component/tree/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/component/tree/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/component/uploader/alioss/api.js create mode 100644 packages/ui/certd-client/src/views/crud/component/uploader/alioss/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/component/uploader/alioss/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/component/uploader/alioss/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/component/uploader/cos/api.js create mode 100644 packages/ui/certd-client/src/views/crud/component/uploader/cos/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/component/uploader/cos/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/component/uploader/cos/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/component/uploader/cropper/api.js create mode 100644 packages/ui/certd-client/src/views/crud/component/uploader/cropper/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/component/uploader/cropper/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/component/uploader/cropper/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/component/uploader/form/api.js create mode 100644 packages/ui/certd-client/src/views/crud/component/uploader/form/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/component/uploader/form/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/component/uploader/form/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/component/uploader/qiniu/api.js create mode 100644 packages/ui/certd-client/src/views/crud/component/uploader/qiniu/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/component/uploader/qiniu/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/component/uploader/qiniu/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/debug/select/api.js create mode 100644 packages/ui/certd-client/src/views/crud/debug/select/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/debug/select/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/debug/select/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/dict/cloneable/api.js create mode 100644 packages/ui/certd-client/src/views/crud/dict/cloneable/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/dict/cloneable/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/dict/cloneable/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/dict/prototype/api.js create mode 100644 packages/ui/certd-client/src/views/crud/dict/prototype/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/dict/prototype/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/dict/prototype/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/dict/shared/manager/api.js create mode 100644 packages/ui/certd-client/src/views/crud/dict/shared/manager/crud.tsx create mode 100644 packages/ui/certd-client/src/views/crud/dict/shared/manager/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/dict/shared/manager/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/dict/shared/shared-dict.ts create mode 100644 packages/ui/certd-client/src/views/crud/dict/shared/use/api.js create mode 100644 packages/ui/certd-client/src/views/crud/dict/shared/use/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/dict/shared/use/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/dict/shared/use/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/dict/single/api.js create mode 100644 packages/ui/certd-client/src/views/crud/dict/single/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/dict/single/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/dict/single/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/column-resize/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/column-resize/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/column-resize/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/column-resize/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/column-sort/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/column-sort/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/column-sort/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/column-sort/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/columns-set/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/columns-set/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/columns-set/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/columns-set/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/editable-row/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/editable-row/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/editable-row/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/editable-row/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/editable/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/editable/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/editable/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/editable/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/expand/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/expand/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/expand/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/expand/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/filter/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/filter/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/filter/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/filter/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/fixed/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/fixed/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/fixed/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/fixed/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/header-group/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/header-group/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/header-group/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/header-group/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/height/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/height/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/height/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/height/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/hide/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/hide/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/hide/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/hide/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/index/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/index/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/index/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/index/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/local-v-model/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/local-v-model/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/local-v-model/local.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/local/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/local/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/merge/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/merge/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/merge/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/merge/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/remove/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/remove/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/remove/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/remove/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/search-multi/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/search-multi/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/search-multi/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/search-multi/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/search/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/search/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/search/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/search/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/selection-radio/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/selection-radio/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/selection-radio/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/selection-radio/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/selection/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/selection/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/selection/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/selection/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/sortable/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/sortable/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/sortable/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/sortable/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/tree/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/tree/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/tree/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/tree/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/value-builder/api.js create mode 100644 packages/ui/certd-client/src/views/crud/feature/value-builder/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/feature/value-builder/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/feature/value-builder/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/form/base/api.js create mode 100644 packages/ui/certd-client/src/views/crud/form/base/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/form/base/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/form/base/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/form/custom-form/api.js create mode 100644 packages/ui/certd-client/src/views/crud/form/custom-form/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/form/custom-form/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/form/custom-form/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/form/drawer/api.js create mode 100644 packages/ui/certd-client/src/views/crud/form/drawer/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/form/drawer/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/form/drawer/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/form/group-tabs/api.js create mode 100644 packages/ui/certd-client/src/views/crud/form/group-tabs/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/form/group-tabs/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/form/group-tabs/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/form/group/api.js create mode 100644 packages/ui/certd-client/src/views/crud/form/group/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/form/group/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/form/group/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/form/helper/api.js create mode 100644 packages/ui/certd-client/src/views/crud/form/helper/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/form/helper/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/form/helper/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/form/independent/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/form/independent/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/form/inner/api.js create mode 100644 packages/ui/certd-client/src/views/crud/form/inner/area/api.js create mode 100644 packages/ui/certd-client/src/views/crud/form/inner/area/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/form/inner/area/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/form/inner/area/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/form/inner/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/form/inner/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/form/inner/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/form/layout-flex/api.js create mode 100644 packages/ui/certd-client/src/views/crud/form/layout-flex/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/form/layout-flex/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/form/layout-flex/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/form/layout-grid/api.js create mode 100644 packages/ui/certd-client/src/views/crud/form/layout-grid/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/form/layout-grid/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/form/layout-grid/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/form/layout/api.js create mode 100644 packages/ui/certd-client/src/views/crud/form/layout/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/form/layout/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/form/layout/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/form/nest/api.js create mode 100644 packages/ui/certd-client/src/views/crud/form/nest/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/form/nest/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/form/nest/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/form/new-page/api.js create mode 100644 packages/ui/certd-client/src/views/crud/form/new-page/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/form/new-page/edit.vue create mode 100644 packages/ui/certd-client/src/views/crud/form/new-page/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/form/new-page/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/form/reset/api.js create mode 100644 packages/ui/certd-client/src/views/crud/form/reset/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/form/reset/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/form/reset/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/form/single-column/api.js create mode 100644 packages/ui/certd-client/src/views/crud/form/single-column/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/form/single-column/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/form/single-column/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/form/validation/api.js create mode 100644 packages/ui/certd-client/src/views/crud/form/validation/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/form/validation/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/form/validation/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/home/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/home/page-cover/helper.js create mode 100644 packages/ui/certd-client/src/views/crud/home/page-cover/image/crud.png create mode 100644 packages/ui/certd-client/src/views/crud/home/page-cover/image/darkblue@2x.png create mode 100644 packages/ui/certd-client/src/views/crud/home/page-cover/image/logo.svg create mode 100644 packages/ui/certd-client/src/views/crud/home/page-cover/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/row-handle/dropdown/api.js create mode 100644 packages/ui/certd-client/src/views/crud/row-handle/dropdown/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/row-handle/dropdown/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/row-handle/dropdown/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/row-handle/tooltip/api.js create mode 100644 packages/ui/certd-client/src/views/crud/row-handle/tooltip/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/row-handle/tooltip/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/row-handle/tooltip/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/slots/cell/api.js create mode 100644 packages/ui/certd-client/src/views/crud/slots/cell/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/slots/cell/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/slots/cell/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/slots/form-item/api.js create mode 100644 packages/ui/certd-client/src/views/crud/slots/form-item/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/slots/form-item/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/slots/form-item/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/slots/form/api.js create mode 100644 packages/ui/certd-client/src/views/crud/slots/form/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/slots/form/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/slots/form/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/slots/layout/api.js create mode 100644 packages/ui/certd-client/src/views/crud/slots/layout/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/slots/layout/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/slots/layout/mock.js create mode 100644 packages/ui/certd-client/src/views/crud/slots/search/api.js create mode 100644 packages/ui/certd-client/src/views/crud/slots/search/crud.jsx create mode 100644 packages/ui/certd-client/src/views/crud/slots/search/index.vue create mode 100644 packages/ui/certd-client/src/views/crud/slots/search/mock.js create mode 100644 packages/ui/certd-client/src/views/framework/error/404.vue create mode 100644 packages/ui/certd-client/src/views/framework/home/index.vue create mode 100644 packages/ui/certd-client/src/views/framework/home/page-cover/helper.js create mode 100644 packages/ui/certd-client/src/views/framework/home/page-cover/image/crud.png create mode 100644 packages/ui/certd-client/src/views/framework/home/page-cover/image/darkblue@2x.png create mode 100644 packages/ui/certd-client/src/views/framework/home/page-cover/image/logo.svg create mode 100644 packages/ui/certd-client/src/views/framework/home/page-cover/index.vue create mode 100644 packages/ui/certd-client/src/views/framework/login/index.vue create mode 100644 packages/ui/certd-client/src/views/framework/register/index.vue create mode 100644 packages/ui/certd-client/src/views/sys/authority/permission/api.js create mode 100644 packages/ui/certd-client/src/views/sys/authority/permission/crud.jsx create mode 100644 packages/ui/certd-client/src/views/sys/authority/permission/fs-permission-tree.vue create mode 100644 packages/ui/certd-client/src/views/sys/authority/permission/index.vue create mode 100644 packages/ui/certd-client/src/views/sys/authority/role/api.js create mode 100644 packages/ui/certd-client/src/views/sys/authority/role/crud.jsx create mode 100644 packages/ui/certd-client/src/views/sys/authority/role/index.vue create mode 100644 packages/ui/certd-client/src/views/sys/authority/user/api.js create mode 100644 packages/ui/certd-client/src/views/sys/authority/user/crud.jsx create mode 100644 packages/ui/certd-client/src/views/sys/authority/user/index.vue create mode 100644 packages/ui/certd-client/tailwind.config.js create mode 100644 packages/ui/certd-client/tests/unit/example.spec.ts create mode 100644 packages/ui/certd-client/tsconfig.json create mode 100644 packages/ui/certd-client/vite.config.ts create mode 100644 packages/ui/certd-client/windi.config.js diff --git a/.gitignore b/.gitignore index ccedd9ff..3fda4751 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,32 @@ # IntelliJ project files +.vscode/ +node_modules/ +npm-debug.log +yarn-error.log +yarn.lock +package-lock.json +/.idea/ +*/**/dist +*/**/pnpm-lock.yaml +*/**/stats.html .idea *.iml out gen -node_modules/ -packages/*/test/*-private.js +/test/*.private.* + +/*.log + +/packages/ui/*/.idea + +/packages/ui/*/node_modules + +/packages/*/node_modules +/packages/ui/certd-server/tmp/ +/packages/ui/certd-ui/dist/ +/other +/dev-sidecar-test +/packages/core/certd/yarn.lock +/packages/test +/test/own +/pnpm-lock.yaml diff --git a/packages/ui/certd-client/.browserslistrc b/packages/ui/certd-client/.browserslistrc new file mode 100644 index 00000000..214388fe --- /dev/null +++ b/packages/ui/certd-client/.browserslistrc @@ -0,0 +1,3 @@ +> 1% +last 2 versions +not dead diff --git a/packages/ui/certd-client/.env b/packages/ui/certd-client/.env new file mode 100644 index 00000000..4933b20f --- /dev/null +++ b/packages/ui/certd-client/.env @@ -0,0 +1,3 @@ +VITE_APP_API=/api +#登录与权限关闭 +VITE_APP_PM_ENABLED=true diff --git a/packages/ui/certd-client/.env.debug b/packages/ui/certd-client/.env.debug new file mode 100644 index 00000000..6a532d74 --- /dev/null +++ b/packages/ui/certd-client/.env.debug @@ -0,0 +1,2 @@ +#登录与权限开启 +VITE_APP_PM_ENABLED=false diff --git a/packages/ui/certd-client/.env.debugpm b/packages/ui/certd-client/.env.debugpm new file mode 100644 index 00000000..c3b69a80 --- /dev/null +++ b/packages/ui/certd-client/.env.debugpm @@ -0,0 +1,2 @@ +#登录与权限开启 +VITE_APP_PM_ENABLED=true diff --git a/packages/ui/certd-client/.env.pm b/packages/ui/certd-client/.env.pm new file mode 100644 index 00000000..c3b69a80 --- /dev/null +++ b/packages/ui/certd-client/.env.pm @@ -0,0 +1,2 @@ +#登录与权限开启 +VITE_APP_PM_ENABLED=true diff --git a/packages/ui/certd-client/.env.production b/packages/ui/certd-client/.env.production new file mode 100644 index 00000000..bc3dbcb7 --- /dev/null +++ b/packages/ui/certd-client/.env.production @@ -0,0 +1,3 @@ +VITE_APP_API=http://www.docmirror.cn:7001/api +#登录与权限开启 +VITE_APP_PM_ENABLED=true diff --git a/packages/ui/certd-client/.eslintignore b/packages/ui/certd-client/.eslintignore new file mode 100644 index 00000000..eb79dd5f --- /dev/null +++ b/packages/ui/certd-client/.eslintignore @@ -0,0 +1,2 @@ +node_modules +.idea diff --git a/packages/ui/certd-client/.eslintrc.js b/packages/ui/certd-client/.eslintrc.js new file mode 100644 index 00000000..a10cc42d --- /dev/null +++ b/packages/ui/certd-client/.eslintrc.js @@ -0,0 +1,76 @@ +module.exports = { + root: true, + env: { + browser: true, + node: true, + es6: true + }, + parser: "vue-eslint-parser", + parserOptions: { + parser: "@typescript-eslint/parser", + ecmaVersion: 2020, + sourceType: "module", + jsxPragma: "React", + ecmaFeatures: { + jsx: true, + tsx: true + } + }, + extends: [ + "plugin:vue/vue3-recommended", + "plugin:@typescript-eslint/recommended", + "plugin:prettier/recommended", + "prettier" + ], + rules: { + //"max-len": [0, 200, 2, { ignoreUrls: true }], + "@typescript-eslint/ban-ts-ignore": "off", + "@typescript-eslint/explicit-function-return-type": "off", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-var-requires": "off", + "@typescript-eslint/no-empty-function": "off", + "@typescript-eslint/no-use-before-define": "off", + "@typescript-eslint/ban-ts-comment": "off", + "@typescript-eslint/ban-types": "off", + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/explicit-module-boundary-types": "off" + // "@typescript-eslint/no-unused-vars": [ + // "error", + // { + // argsIgnorePattern: "^h$", + // varsIgnorePattern: "^h$", + // }, + // ], + // "no-unused-vars": [ + // "error", + // { + // argsIgnorePattern: "^h$", + // varsIgnorePattern: "^h$", + // }, + // ], + // "vue/custom-event-name-casing": "off", + // "no-use-before-define": "off", + // "space-before-function-paren": "off", + + // "vue/attributes-order": "off", + // "vue/one-component-per-file": "off", + // "vue/html-closing-bracket-newline": "off", + // "vue/max-attributes-per-line": "off", + // "vue/multiline-html-element-content-newline": "off", + // "vue/singleline-html-element-content-newline": "off", + // "vue/attribute-hyphenation": "off", + // "vue/require-default-prop": "off", + // "vue/html-self-closing": [ + // "error", + // { + // html: { + // void: "always", + // normal: "never", + // component: "always", + // }, + // svg: "always", + // math: "always", + // }, + // ], + } +}; diff --git a/packages/ui/certd-client/.gitignore b/packages/ui/certd-client/.gitignore new file mode 100644 index 00000000..980be95d --- /dev/null +++ b/packages/ui/certd-client/.gitignore @@ -0,0 +1,11 @@ +node_modules +.DS_Store +dist +dist-ssr +*.local +/stats.html +yarn.lock +.idea +/.idea/ +yarn-error.log +vite-profile.cpuprofile diff --git a/packages/ui/certd-client/.npmignore b/packages/ui/certd-client/.npmignore new file mode 100644 index 00000000..b6c09bbd --- /dev/null +++ b/packages/ui/certd-client/.npmignore @@ -0,0 +1,2 @@ +node_modules +/stats.html diff --git a/packages/ui/certd-client/.prettierrc b/packages/ui/certd-client/.prettierrc new file mode 100644 index 00000000..61e99f7c --- /dev/null +++ b/packages/ui/certd-client/.prettierrc @@ -0,0 +1,5 @@ +{ + + "trailingComma": "none", + "printWidth": 220 +} diff --git a/packages/ui/certd-client/CHANGELOG.md b/packages/ui/certd-client/CHANGELOG.md new file mode 100644 index 00000000..ccaa88d1 --- /dev/null +++ b/packages/ui/certd-client/CHANGELOG.md @@ -0,0 +1,12 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [0.10.5](https://github.com/fast-crud/fast-crud/compare/v0.10.4...v0.10.5) (2021-07-01) + + +### Performance Improvements + +* fs-admin 与crud demo ([4e6b20f](https://github.com/fast-crud/fast-crud/commit/4e6b20fe19434460853841f371b9fd5f16e5e2d3)) +* fs-admin纳入子模块 ([2940d30](https://github.com/fast-crud/fast-crud/commit/2940d30f419bf4bde1e8e791f1fbdb9184818285)) diff --git a/packages/ui/certd-client/LICENSE b/packages/ui/certd-client/LICENSE new file mode 100644 index 00000000..e9513c2e --- /dev/null +++ b/packages/ui/certd-client/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 fast-crud + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/ui/certd-client/README.md b/packages/ui/certd-client/README.md new file mode 100644 index 00000000..b360e070 --- /dev/null +++ b/packages/ui/certd-client/README.md @@ -0,0 +1,37 @@ +# fs-admin-antdv + +基于vue3、antdv 的 admin管理后台脚手架 +更多信息请参考: [fast-crud](https://github.com/fast-crud/fast-crud) +# server端 + +## fs-server-js +https://github.com/fast-crud/fs-server-js + +# 其他相关项目 + * [fast-crud](https://github.com/fast-crud/fast-crud) crud主项目 + * [fs-admin-element](https://github.com/fast-crud/fs-admin-element) element版示例 + * [fs-admin-naive](https://github.com/fast-crud/fs-admin-naive-ui) naive版示例 + * [fs-in-vben-starter](https://github.com/fast-crud/fs-in-vben-starter) vben示例 + +# 感谢 + +### 依赖 +* [vue](https://github.com/vuejs/vue-next) +* [vue-router](https://github.com/vuejs/vue-router-next) +* [antdv 2x](https://github.com/vueComponent/ant-design-vue) +* [vitejs](https://github.com/vitejs/vite) +* [pinia](https://github.com/posva/pinia) +* [purge-icons](https://github.com/antfu/purge-icons) + +### 参考如下项目 +* [d2-admin](https://github.com/d2-projects/d2-admin) +* [antdv-pro](https://github.com/vueComponent/ant-design-vue-pro) +* [vben-admin](https://github.com/anncwb/vue-vben-admin) + +感谢这些优秀的项目 + + + + + + diff --git a/packages/ui/certd-client/build/modify-vars.ts b/packages/ui/certd-client/build/modify-vars.ts new file mode 100644 index 00000000..c6cf20a3 --- /dev/null +++ b/packages/ui/certd-client/build/modify-vars.ts @@ -0,0 +1,11 @@ +// import { getThemeVariables } from "ant-design-vue/dist/theme"; +// import path from "path"; +// const resolve = path.resolve; +export function generateModifyVars(dark = false) { + //const modifyVars = getThemeVariables({ dark }); + // const vars = `${resolve("src/style/theme/index.less")}`; + return { + //...modifyVars + // hack: `true; @import (reference) "${vars}";` + }; +} diff --git a/packages/ui/certd-client/build/theme-colors.ts b/packages/ui/certd-client/build/theme-colors.ts new file mode 100644 index 00000000..41396ef0 --- /dev/null +++ b/packages/ui/certd-client/build/theme-colors.ts @@ -0,0 +1,72 @@ +import { generate } from "@ant-design/colors"; + +export const primaryColor = "#1890ff"; + +export const darkMode = "light"; + +type Fn = (...arg: any) => any; + +export interface GenerateColorsParams { + mixLighten: Fn; + mixDarken: Fn; + tinycolor: any; + color?: string; +} + +export function generateAntColors(color: string) { + return generate(color, { + theme: "default" + }); +} + +export function getThemeColors(color?: string) { + const tc = color || primaryColor; + const colors = generateAntColors(tc); + const primary = colors[5]; + const modeColors = generateAntColors(primary); + + return [...colors, ...modeColors]; +} + +export function generateColors({ color = primaryColor, mixLighten, mixDarken, tinycolor }: GenerateColorsParams) { + const arr = new Array(19).fill(0); + const lightens = arr.map((_t, i) => { + return mixLighten(color, i / 5); + }); + + const darkens = arr.map((_t, i) => { + return mixDarken(color, i / 5); + }); + + const alphaColors = arr.map((_t, i) => { + return tinycolor(color) + .setAlpha(i / 20) + .toRgbString(); + }); + + const shortAlphaColors = alphaColors.map((item) => item.replace(/\s/g, "").replace(/0\./g, ".")); + + const tinycolorLightens = arr + .map((_t, i) => { + return tinycolor(color) + .lighten(i * 5) + .toHexString(); + }) + .filter((item) => item !== "#ffffff"); + + const tinycolorDarkens = arr + .map((_t, i) => { + return tinycolor(color) + .darken(i * 5) + .toHexString(); + }) + .filter((item) => item !== "#000000"); + return [ + ...lightens, + ...darkens, + ...alphaColors, + ...shortAlphaColors, + ...tinycolorDarkens, + ...tinycolorLightens + ].filter((item) => !item.includes("-")); +} diff --git a/packages/ui/certd-client/build/theme-plugin.ts b/packages/ui/certd-client/build/theme-plugin.ts new file mode 100644 index 00000000..d223642b --- /dev/null +++ b/packages/ui/certd-client/build/theme-plugin.ts @@ -0,0 +1,68 @@ +/** + * Vite plugin for website theme color switching + * https://github.com/anncwb/vite-plugin-theme + */ +import type { Plugin } from "vite"; +import path from "path"; +import { viteThemePlugin, mixLighten, mixDarken, tinycolor, antdDarkThemePlugin } from "vite-plugin-theme"; +import { getThemeColors, generateColors } from "./theme-colors"; +import { generateModifyVars } from "./modify-vars"; + +export function configThemePlugin(isBuild: boolean): Plugin[] { + const colors = generateColors({ + mixDarken, + mixLighten, + tinycolor + }); + const colorVariables = [...getThemeColors(), ...colors]; + const plugin = [ + viteThemePlugin({ + // resolveSelector: (s) => { + // s = s.trim(); + // switch (s) { + // case ".ant-steps-item-process .ant-steps-item-icon > .ant-steps-icon": + // return ".ant-steps-item-icon > .ant-steps-icon"; + // case ".ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled)": + // case ".ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):hover": + // case ".ant-radio-button-wrapper-checked:not(.ant-radio-button-wrapper-disabled):active": + // return s; + // case ".ant-steps-item-icon > .ant-steps-icon": + // return s; + // } + // return `[data-theme] ${s}`; + // }, + resolveSelector: (s) => { + s = s.trim(); + if (s === ".ant-btn:hover,.ant-btn:focus") { + // console.log("ssss", s); + return ".theme-discard-xxxxxxx"; + } + return s; + }, + colorVariables + }), + antdDarkThemePlugin({ + preloadFiles: [ + path.resolve(process.cwd(), "node_modules/ant-design-vue/dist/antd.less"), + path.resolve(process.cwd(), "src/style/theme/index.less") + ], + filter: (id) => (isBuild ? !id.endsWith("antd.less") : true), + // extractCss: false, + darkModifyVars: { + ...generateModifyVars(true), + "text-color": "#c9d1d9", + "text-color-base": "#c9d1d9", + "component-background": "#151515", + // black: '#0e1117', + // #8b949e + "text-color-secondary": "#8b949e", + "border-color-base": "#303030", + // 'border-color-split': '#30363d', + "item-active-bg": "#111b26", + "app-content-background": "rgb(255 255 255 / 4%)" + } + }) + ]; + + return (plugin as unknown) as Plugin[]; +} diff --git a/packages/ui/certd-client/index.html b/packages/ui/certd-client/index.html new file mode 100644 index 00000000..aac3b8bf --- /dev/null +++ b/packages/ui/certd-client/index.html @@ -0,0 +1,26 @@ + + + + + + + antdv-fast-crud + + + +
+ + +
+ + + diff --git a/packages/ui/certd-client/package.json b/packages/ui/certd-client/package.json new file mode 100644 index 00000000..a629e40c --- /dev/null +++ b/packages/ui/certd-client/package.json @@ -0,0 +1,120 @@ +{ + "name": "@fast-crud/fs-admin-antdv", + "version": "1.8.4", + "private": true, + "scripts": { + "dev": "vite", + "dev:pm": "vite --mode pm", + "dev:force": "vite --force", + "debug": "vite --mode debug", + "debug:pm": "vite --mode debugpm", + "debug:force": "vite --force --mode debug", + "build": "vite build ", + "serve": "vite preview", + "preview": "vite preview", + "pretty-quick": "pretty-quick", + "lint-fix": "eslint --fix --ext .js --ext .jsx --ext .vue src/", + "upgrade": "yarn upgrade-interactive --latest" + }, + "author": "Greper", + "license": "MIT", + "dependencies": { + "@ant-design/colors": "^6.0.0", + "@ant-design/icons-vue": "^6.0.1", + "@fast-crud/fast-crud": "^1.8.4", + "@fast-crud/fast-extends": "^1.8.4", + "@fast-crud/ui-antdv": "^1.8.4", + "@iconify/iconify": "^3.0.1", + "@iconify/json": "^2.1.151", + "@purge-icons/generated": "^0.9.0", + "@soerenmartius/vue3-clipboard": "^0.1.2", + "ant-design-vue": "^3.2.15", + "axios": "^1.2.1", + "axios-mock-adapter": "^1.21.2", + "base64-js": "^1.5.1", + "better-scroll": "^2.5.0", + "china-division": "^2.4.0", + "core-js": "^3.26.1", + "cos-js-sdk-v5": "^1.4.15-beta.0", + "cropperjs": "^1.5.13", + "deepdash-es": "5.3.5", + "highlight.js": "^11.7.0", + "lodash-es": "^4.17.15", + "mitt": "^3.0.0", + "nprogress": "^0.2.0", + "object-assign": "^4.1.1", + "pinia": "2.0.28", + "qiniu-js": "^3.4.1", + "sortablejs": "^1.14.0", + "vue": "^3.2.45", + "vue-cropperjs": "^5.0.0", + "vue-i18n": "^9.2.2", + "vue-router": "^4.1.5", + "vuedraggable": "^4.0.1" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "^23.0.4", + "@rollup/plugin-node-resolve": "^15.0.1", + "@types/chai": "^4.3.4", + "@types/lodash-es": "^4.17.6", + "@types/mocha": "^10.0.1", + "@types/node": "^18.11.15", + "@typescript-eslint/eslint-plugin": "^5.46.1", + "@typescript-eslint/parser": "^5.46.1", + "@vitejs/plugin-legacy": "^3.0.1", + "@vitejs/plugin-vue": "^4.0.0", + "@vitejs/plugin-vue-jsx": "^3.0.0", + "@vue/compiler-sfc": "^3.2.45", + "@vue/eslint-config-typescript": "^11.0.2", + "@vue/test-utils": "^2.2.6", + "autoprefixer": "^10.4.12", + "caller-path": "^4.0.0", + "chai": "^4.3.7", + "eslint": "8.29.0", + "eslint-config-prettier": "^8.1.0", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-prettier": "^4.2.1", + "eslint-plugin-promise": "^6.0.1", + "eslint-plugin-vue": "^9.8.0", + "esno": "^0.16.3", + "husky": "^8.0.2", + "less": "^4.1.3", + "less-loader": "^11.0.0", + "lint-staged": "^13.1.0", + "postcss": "^8.4.20", + "prettier": "2.8.1", + "pretty-quick": "^3.1.3", + "rimraf": "^3.0.2", + "rollup": "^3.7.4", + "rollup-plugin-visualizer": "^5.8.2", + "stylelint": "^14.16.0", + "stylelint-config-prettier": "^9.0.4", + "stylelint-order": "^5.0.0", + "tailwindcss": "^3.2.4", + "ts-node": "^10.9.1", + "typescript": "4.9.4", + "vite": "^4.0.1", + "vite-plugin-compression": "^0.5.1", + "vite-plugin-optimize-persist": "^0.1.2", + "vite-plugin-package-config": "^0.1.1", + "vite-plugin-purge-icons": "^0.9.2", + "vite-plugin-theme": "^0.8.1", + "vite-plugin-windicss": "^1.8.10", + "vue-eslint-parser": "^9.1.0", + "windicss": "^3.5.6" + }, + "husky": { + "hooks": { + "pre-commit": "pretty-quick --staged" + } + }, + "gitHead": "9c2162697f3affea22c9a8cbc0ca74f4034ab27e", + "vite": { + "optimizeDeps": { + "include": [ + "@iconify/iconify" + ] + } + } +} diff --git a/packages/ui/certd-client/public/favicon.ico b/packages/ui/certd-client/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..df36fcfb72584e00488330b560ebcf34a41c64c2 GIT binary patch literal 4286 zcmds*O-Phc6o&64GDVCEQHxsW(p4>LW*W<827=Unuo8sGpRux(DN@jWP-e29Wl%wj zY84_aq9}^Am9-cWTD5GGEo#+5Fi2wX_P*bo+xO!)p*7B;iKlbFd(U~_d(U?#hLj56 zPhFkj-|A6~Qk#@g^#D^U0XT1cu=c-vu1+SElX9NR;kzAUV(q0|dl0|%h|dI$%VICy zJnu2^L*Te9JrJMGh%-P79CL0}dq92RGU6gI{v2~|)p}sG5x0U*z<8U;Ij*hB9z?ei z@g6Xq-pDoPl=MANPiR7%172VA%r)kevtV-_5H*QJKFmd;8yA$98zCxBZYXTNZ#QFk2(TX0;Y2dt&WitL#$96|gJY=3xX zpCoi|YNzgO3R`f@IiEeSmKrPSf#h#Qd<$%Ej^RIeeYfsxhPMOG`S`Pz8q``=511zm zAm)MX5AV^5xIWPyEu7u>qYs?pn$I4nL9J!=K=SGlKLXpE<5x+2cDTXq?brj?n6sp= zphe9;_JHf40^9~}9i08r{XM$7HB!`{Ys~TK0kx<}ZQng`UPvH*11|q7&l9?@FQz;8 zx!=3<4seY*%=OlbCbcae?5^V_}*K>Uo6ZWV8mTyE^B=DKy7-sdLYkR5Z?paTgK-zyIkKjIcpyO z{+uIt&YSa_$QnN_@t~L014dyK(fOOo+W*MIxbA6Ndgr=Y!f#Tokqv}n<7-9qfHkc3 z=>a|HWqcX8fzQCT=dqVbogRq!-S>H%yA{1w#2Pn;=e>JiEj7Hl;zdt-2f+j2%DeVD zsW0Ab)ZK@0cIW%W7z}H{&~yGhn~D;aiP4=;m-HCo`BEI+Kd6 z={Xwx{TKxD#iCLfl2vQGDitKtN>z|-AdCN|$jTFDg0m3O`WLD4_s#$S literal 0 HcmV?d00001 diff --git a/packages/ui/certd-client/public/images/logo-certd/logo.svg b/packages/ui/certd-client/public/images/logo-certd/logo.svg new file mode 100644 index 00000000..edcdefbe --- /dev/null +++ b/packages/ui/certd-client/public/images/logo-certd/logo.svg @@ -0,0 +1,7 @@ + + + diff --git a/packages/ui/certd-client/public/images/logo-certd/rect-black.svg b/packages/ui/certd-client/public/images/logo-certd/rect-black.svg new file mode 100644 index 00000000..19bf439f --- /dev/null +++ b/packages/ui/certd-client/public/images/logo-certd/rect-black.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 让你的证书永不过期 + + + diff --git a/packages/ui/certd-client/public/images/logo-certd/rect.svg b/packages/ui/certd-client/public/images/logo-certd/rect.svg new file mode 100644 index 00000000..acc2f41c --- /dev/null +++ b/packages/ui/certd-client/public/images/logo-certd/rect.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 让你的证书永不过期 + + + diff --git a/packages/ui/certd-client/public/images/logo-certd/square.svg b/packages/ui/certd-client/public/images/logo-certd/square.svg new file mode 100644 index 00000000..026dd978 --- /dev/null +++ b/packages/ui/certd-client/public/images/logo-certd/square.svg @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/packages/ui/certd-client/public/images/logo/logo.svg b/packages/ui/certd-client/public/images/logo/logo.svg new file mode 100644 index 00000000..edcdefbe --- /dev/null +++ b/packages/ui/certd-client/public/images/logo/logo.svg @@ -0,0 +1,7 @@ + + + diff --git a/packages/ui/certd-client/public/images/logo/rect-black.svg b/packages/ui/certd-client/public/images/logo/rect-black.svg new file mode 100644 index 00000000..a57352ec --- /dev/null +++ b/packages/ui/certd-client/public/images/logo/rect-black.svg @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ui/certd-client/public/images/logo/rect.svg b/packages/ui/certd-client/public/images/logo/rect.svg new file mode 100644 index 00000000..acc2f41c --- /dev/null +++ b/packages/ui/certd-client/public/images/logo/rect.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 让你的证书永不过期 + + + diff --git a/packages/ui/certd-client/public/images/logo/square.svg b/packages/ui/certd-client/public/images/logo/square.svg new file mode 100644 index 00000000..1b1395a1 --- /dev/null +++ b/packages/ui/certd-client/public/images/logo/square.svg @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ui/certd-client/public/index.css b/packages/ui/certd-client/public/index.css new file mode 100644 index 00000000..0950b050 --- /dev/null +++ b/packages/ui/certd-client/public/index.css @@ -0,0 +1,12 @@ +html, body, #app { height: 100%; margin: 0; padding: 0; width: 100%;} +.fs-bootstrap { background-color: #474949; height: 100%; display: flex; flex-direction: column;position: fixed;width: 100% } +.fs-bootstrap__main {flex:1; user-select: none; width: 100%; flex-grow: 1; display: flex; justify-content: center; align-items: center; flex-direction: column; } +.fs-bootstrap__footer { width: 100%; flex-grow: 0; text-align: center; padding: 10px 0; } +.fs-bootstrap__footer > a { font-size: 12px; color: #ABABAB; text-decoration: none; } +.fs-bootstrap__loading {box-sizing: border-box; height: 50px; width: 50px; margin-bottom: 5px;border:5px solid #333333;border-bottom:#aaa 5px solid; + border-radius:1000px; animation:load 1.1s infinite linear;-webkit-animation:load 1.1s infinite linear;-moz-animation:load 1.1s infinite linear; -o-animation:load 1.1s infinite linear; +} +@keyframes load {from {transform:rotate(0deg);-ms-transform:rotate(0deg);}to { transform:rotate(360deg);-ms-transform:rotate(360deg); } +}@-webkit-keyframes load {from {-webkit-transform:rotate(0deg); }to { -webkit-transform:rotate(360deg);} + }@-moz-keyframes load { from { -moz-transform:rotate(0deg); } to { -moz-transform:rotate(360deg);} + }@-o-keyframes load { from { -o-transform:rotate(0deg);} to { -o-transform:rotate(360deg);}} diff --git a/packages/ui/certd-client/public/index.html b/packages/ui/certd-client/public/index.html new file mode 100644 index 00000000..3e5a1396 --- /dev/null +++ b/packages/ui/certd-client/public/index.html @@ -0,0 +1,17 @@ + + + + + + + + <%= htmlWebpackPlugin.options.title %> + + + +
+ + + diff --git a/packages/ui/certd-client/public/logo.svg b/packages/ui/certd-client/public/logo.svg new file mode 100644 index 00000000..1b1395a1 --- /dev/null +++ b/packages/ui/certd-client/public/logo.svg @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ui/certd-client/src/App.vue b/packages/ui/certd-client/src/App.vue new file mode 100644 index 00000000..5059cfa5 --- /dev/null +++ b/packages/ui/certd-client/src/App.vue @@ -0,0 +1,56 @@ + + + diff --git a/packages/ui/certd-client/src/api/modules/api.user.mock.ts b/packages/ui/certd-client/src/api/modules/api.user.mock.ts new file mode 100644 index 00000000..53411901 --- /dev/null +++ b/packages/ui/certd-client/src/api/modules/api.user.mock.ts @@ -0,0 +1,31 @@ +export default [ + { + path: "/login", + method: "post", + handle() { + return { + code: 0, + msg: "success", + data: { + token: "faker token", + expire: 10000 + } + }; + } + }, + { + path: "/sys/authority/user/mine", + method: "get", + handle() { + return { + code: 0, + msg: "success", + data: { + id: 1, + username: "username", + nickName: "admin" + } + }; + } + } +]; diff --git a/packages/ui/certd-client/src/api/modules/api.user.ts b/packages/ui/certd-client/src/api/modules/api.user.ts new file mode 100644 index 00000000..ea711596 --- /dev/null +++ b/packages/ui/certd-client/src/api/modules/api.user.ts @@ -0,0 +1,51 @@ +import { request, requestForMock } from "../service"; +import { env } from "/@/utils/util.env"; +/** + * @description: Login interface parameters + */ +export interface LoginReq { + username: string; + password: string; +} + +export interface UserInfoRes { + id: string | number; + username: string; + nickName: string; +} + +export interface LoginRes { + token: string; + expire: number; +} + +export async function login(data: LoginReq): Promise { + if (env.PM_ENABLED === "false") { + //没有开启权限模块,模拟登录 + return await requestForMock({ + url: "/login", + method: "post", + data + }); + } + //如果开启了登录与权限模块,则真实登录 + return await request({ + url: "/login", + method: "post", + data + }); +} + +export async function mine(): Promise { + if (env.PM_ENABLED === "false") { + //没有开启权限模块,模拟登录 + return await requestForMock({ + url: "/sys/authority/user/mine", + method: "post" + }); + } + return await request({ + url: "/sys/authority/user/mine", + method: "post" + }); +} diff --git a/packages/ui/certd-client/src/api/service.ts b/packages/ui/certd-client/src/api/service.ts new file mode 100644 index 00000000..cd8da796 --- /dev/null +++ b/packages/ui/certd-client/src/api/service.ts @@ -0,0 +1,138 @@ +import axios from "axios"; +import { get } from "lodash-es"; +import Adapter from "axios-mock-adapter"; +import { errorLog, errorCreate } from "./tools"; +import { env } from "/src/utils/util.env"; +import { useUserStore } from "../store/modules/user"; +/** + * @description 创建请求实例 + */ +function createService() { + // 创建一个 axios 实例 + const service = axios.create(); + // 请求拦截 + service.interceptors.request.use( + (config) => config, + (error) => { + // 发送失败 + console.log(error); + return Promise.reject(error); + } + ); + // 响应拦截 + service.interceptors.response.use( + (response) => { + if (response.config.responseType === "blob") { + return response; + } + // dataAxios 是 axios 返回数据中的 data + const dataAxios = response.data; + // 这个状态码是和后端约定的 + const { code } = dataAxios; + // 根据 code 进行判断 + if (code === undefined) { + // 如果没有 code 代表这不是项目后端开发的接口 比如可能是 D2Admin 请求最新版本 + errorCreate(`非标准返回:${dataAxios}, ${response.config.url}`); + return dataAxios; + } else { + // 有 code 代表这是一个后端接口 可以进行进一步的判断 + switch (code) { + case 0: + // [ 示例 ] code === 0 代表没有错误 + // @ts-ignore + if (response.config.unpack === false) { + //如果不需要解包 + return dataAxios; + } + return dataAxios.data; + default: + // 不是正确的 code + errorCreate(`${dataAxios.msg}: ${response.config.url}`); + return dataAxios; + } + } + }, + (error) => { + const status = get(error, "response.status"); + switch (status) { + case 400: + error.message = "请求错误"; + break; + case 401: + error.message = "未授权,请登录"; + break; + case 403: + error.message = "拒绝访问"; + break; + case 404: + error.message = `请求地址出错: ${error.response.config.url}`; + break; + case 408: + error.message = "请求超时"; + break; + case 500: + error.message = "服务器内部错误"; + break; + case 501: + error.message = "服务未实现"; + break; + case 502: + error.message = "网关错误"; + break; + case 503: + error.message = "服务不可用"; + break; + case 504: + error.message = "网关超时"; + break; + case 505: + error.message = "HTTP版本不受支持"; + break; + default: + break; + } + errorLog(error); + if (status === 401) { + const userStore = useUserStore(); + userStore.logout(); + } + return Promise.reject(error); + } + ); + return service; +} + +/** + * @description 创建请求方法 + * @param {Object} service axios 实例 + */ +function createRequestFunction(service) { + return function (config) { + const configDefault = { + headers: { + "Content-Type": get(config, "headers.Content-Type", "application/json") + }, + timeout: 5000, + baseURL: env.API, + data: {} + }; + const userStore = useUserStore(); + const token = userStore.getToken; + if (token != null) { + // @ts-ignore + configDefault.headers.Authorization = token; + } + return service(Object.assign(configDefault, config)); + }; +} + +// 用于真实网络请求的实例和请求方法 +export const service = createService(); +export const request = createRequestFunction(service); + +// 用于模拟网络请求的实例和请求方法 +export const serviceForMock = createService(); +export const requestForMock = createRequestFunction(serviceForMock); + +// 网络请求数据模拟工具 +export const mock = new Adapter(serviceForMock, { delayResponse: 200 }); diff --git a/packages/ui/certd-client/src/api/tools.ts b/packages/ui/certd-client/src/api/tools.ts new file mode 100644 index 00000000..80fa784b --- /dev/null +++ b/packages/ui/certd-client/src/api/tools.ts @@ -0,0 +1,66 @@ +/** + * @description 安全地解析 json 字符串 + * @param {String} jsonString 需要解析的 json 字符串 + * @param {String} defaultValue 默认值 + */ +import { uiContext } from "@fast-crud/fast-crud"; + +export function parse(jsonString = "{}", defaultValue = {}) { + let result = defaultValue; + try { + result = JSON.parse(jsonString); + } catch (error) { + console.log(error); + } + return result; +} + +/** + * @description 接口请求返回 + * @param {Any} data 返回值 + * @param {String} msg 状态信息 + * @param {Number} code 状态码 + */ +export function response(data = {}, msg = "", code = 0) { + return [200, { code, msg, data }]; +} + +/** + * @description 接口请求返回 正确返回 + * @param {Any} data 返回值 + * @param {String} msg 状态信息 + */ +export function responseSuccess(data = {}, msg = "成功") { + return response(data, msg); +} + +/** + * @description 接口请求返回 错误返回 + * @param {Any} data 返回值 + * @param {String} msg 状态信息 + * @param {Number} code 状态码 + */ +export function responseError(data = {}, msg = "请求失败", code = 500) { + return response(data, msg, code); +} + +/** + * @description 记录和显示错误 + * @param {Error} error 错误对象 + */ +export function errorLog(error) { + // 打印到控制台 + console.error(error); + // 显示提示 + uiContext.get().notification.error({ message: error.message }); +} + +/** + * @description 创建一个错误 + * @param {String} msg 错误信息 + */ +export function errorCreate(msg) { + const error = new Error(msg); + errorLog(error); + throw error; +} diff --git a/packages/ui/certd-client/src/assets/background.svg b/packages/ui/certd-client/src/assets/background.svg new file mode 100644 index 00000000..89c25976 --- /dev/null +++ b/packages/ui/certd-client/src/assets/background.svg @@ -0,0 +1,69 @@ + + + + Group 21 + Created with Sketch. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/packages/ui/certd-client/src/assets/logo.png b/packages/ui/certd-client/src/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f3d2503fc2a44b5053b0837ebea6e87a2d339a43 GIT binary patch literal 6849 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 + * ---------------------------------------------------- + * + * #ade5fc + * #a2fca2 + * #c6b4f0 + * #d36363 + * #fcc28c + * #fc9b9b + * #ffa + * #fff + * #333 + * #62c8f3 + * #888 + * + */ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #333; + color: white; +} + +.hljs-name, +.hljs-strong { + font-weight: bold; +} + +.hljs-code, +.hljs-emphasis { + font-style: italic; +} + +.hljs-tag { + color: #62c8f3; +} + +.hljs-variable, +.hljs-template-variable, +.hljs-selector-id, +.hljs-selector-class { + color: #ade5fc; +} + +.hljs-string, +.hljs-bullet { + color: #a2fca2; +} + +.hljs-type, +.hljs-title, +.hljs-section, +.hljs-attribute, +.hljs-quote, +.hljs-built_in, +.hljs-builtin-name { + color: #ffa; +} + +.hljs-number, +.hljs-symbol, +.hljs-bullet { + color: #d36363; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-literal { + color: #fcc28c; +} + +.hljs-comment, +.hljs-deletion, +.hljs-code { + color: #888; +} + +.hljs-regexp, +.hljs-link { + color: #c6b4f0; +} + +.hljs-meta { + color: #fc9b9b; +} + +.hljs-deletion { + background-color: #fc9b9b; + color: #333; +} + +.hljs-addition { + background-color: #a2fca2; + color: #333; +} + +.hljs a { + color: inherit; +} + +.hljs a:focus, +.hljs a:hover { + color: inherit; + text-decoration: underline; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/androidstudio.css b/packages/ui/certd-client/src/components/highlight-styles/androidstudio.css new file mode 100644 index 00000000..bc8e473b --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/androidstudio.css @@ -0,0 +1,66 @@ +/* +Date: 24 Fev 2015 +Author: Pedro Oliveira +*/ + +.hljs { + color: #a9b7c6; + background: #282b2e; + display: block; + overflow-x: auto; + padding: 0.5em; +} + +.hljs-number, +.hljs-literal, +.hljs-symbol, +.hljs-bullet { + color: #6897BB; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-deletion { + color: #cc7832; +} + +.hljs-variable, +.hljs-template-variable, +.hljs-link { + color: #629755; +} + +.hljs-comment, +.hljs-quote { + color: #808080; +} + +.hljs-meta { + color: #bbb529; +} + +.hljs-string, +.hljs-attribute, +.hljs-addition { + color: #6A8759; +} + +.hljs-section, +.hljs-title, +.hljs-type { + color: #ffc66d; +} + +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #e8bf6a; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/arduino-light.css b/packages/ui/certd-client/src/components/highlight-styles/arduino-light.css new file mode 100644 index 00000000..4b8b7fd3 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/arduino-light.css @@ -0,0 +1,88 @@ +/* + +Arduino® Light Theme - Stefania Mellai + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #FFFFFF; +} + +.hljs, +.hljs-subst { + color: #434f54; +} + +.hljs-keyword, +.hljs-attribute, +.hljs-selector-tag, +.hljs-doctag, +.hljs-name { + color: #00979D; +} + +.hljs-built_in, +.hljs-literal, +.hljs-bullet, +.hljs-code, +.hljs-addition { + color: #D35400; +} + +.hljs-regexp, +.hljs-symbol, +.hljs-variable, +.hljs-template-variable, +.hljs-link, +.hljs-selector-attr, +.hljs-selector-pseudo { + color: #00979D; +} + +.hljs-type, +.hljs-string, +.hljs-selector-id, +.hljs-selector-class, +.hljs-quote, +.hljs-template-tag, +.hljs-deletion { + color: #005C5F; +} + +.hljs-title, +.hljs-section { + color: #880000; + font-weight: bold; +} + +.hljs-comment { + color: rgba(149,165,166,.8); +} + +.hljs-meta-keyword { + color: #728E00; +} + +.hljs-meta { + color: #728E00; + color: #434f54; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} + +.hljs-function { + color: #728E00; +} + +.hljs-number { + color: #8A7B52; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/arta.css b/packages/ui/certd-client/src/components/highlight-styles/arta.css new file mode 100644 index 00000000..75ef3a9e --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/arta.css @@ -0,0 +1,73 @@ +/* +Date: 17.V.2011 +Author: pumbur +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #222; +} + +.hljs, +.hljs-subst { + color: #aaa; +} + +.hljs-section { + color: #fff; +} + +.hljs-comment, +.hljs-quote, +.hljs-meta { + color: #444; +} + +.hljs-string, +.hljs-symbol, +.hljs-bullet, +.hljs-regexp { + color: #ffcc33; +} + +.hljs-number, +.hljs-addition { + color: #00cc66; +} + +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-template-variable, +.hljs-attribute, +.hljs-link { + color: #32aaee; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #6644aa; +} + +.hljs-title, +.hljs-variable, +.hljs-deletion, +.hljs-template-tag { + color: #bb1166; +} + +.hljs-section, +.hljs-doctag, +.hljs-strong { + font-weight: bold; +} + +.hljs-emphasis { + font-style: italic; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/ascetic.css b/packages/ui/certd-client/src/components/highlight-styles/ascetic.css new file mode 100644 index 00000000..48397e88 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/ascetic.css @@ -0,0 +1,45 @@ +/* + +Original style from softwaremaniacs.org (c) Ivan Sagalaev + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: white; + color: black; +} + +.hljs-string, +.hljs-variable, +.hljs-template-variable, +.hljs-symbol, +.hljs-bullet, +.hljs-section, +.hljs-addition, +.hljs-attribute, +.hljs-link { + color: #888; +} + +.hljs-comment, +.hljs-quote, +.hljs-meta, +.hljs-deletion { + color: #ccc; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-section, +.hljs-name, +.hljs-type, +.hljs-strong { + font-weight: bold; +} + +.hljs-emphasis { + font-style: italic; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atelier-cave-dark.css b/packages/ui/certd-client/src/components/highlight-styles/atelier-cave-dark.css new file mode 100644 index 00000000..65428f3b --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atelier-cave-dark.css @@ -0,0 +1,83 @@ +/* Base16 Atelier Cave Dark - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ + +/* Atelier-Cave Comment */ +.hljs-comment, +.hljs-quote { + color: #7e7887; +} + +/* Atelier-Cave Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-regexp, +.hljs-link, +.hljs-tag, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #be4678; +} + +/* Atelier-Cave Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #aa573c; +} + +/* Atelier-Cave Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #2a9292; +} + +/* Atelier-Cave Blue */ +.hljs-title, +.hljs-section { + color: #576ddb; +} + +/* Atelier-Cave Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #955ae7; +} + +.hljs-deletion, +.hljs-addition { + color: #19171c; + display: inline-block; + width: 100%; +} + +.hljs-deletion { + background-color: #be4678; +} + +.hljs-addition { + background-color: #2a9292; +} + +.hljs { + display: block; + overflow-x: auto; + background: #19171c; + color: #8b8792; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atelier-cave-light.css b/packages/ui/certd-client/src/components/highlight-styles/atelier-cave-light.css new file mode 100644 index 00000000..b419f9fd --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atelier-cave-light.css @@ -0,0 +1,85 @@ +/* Base16 Atelier Cave Light - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/cave) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ + +/* Atelier-Cave Comment */ +.hljs-comment, +.hljs-quote { + color: #655f6d; +} + +/* Atelier-Cave Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #be4678; +} + +/* Atelier-Cave Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #aa573c; +} + +/* Atelier-Cave Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #2a9292; +} + +/* Atelier-Cave Blue */ +.hljs-title, +.hljs-section { + color: #576ddb; +} + +/* Atelier-Cave Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #955ae7; +} + +.hljs-deletion, +.hljs-addition { + color: #19171c; + display: inline-block; + width: 100%; +} + +.hljs-deletion { + background-color: #be4678; +} + +.hljs-addition { + background-color: #2a9292; +} + +.hljs { + display: block; + overflow-x: auto; + background: #efecf4; + color: #585260; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atelier-dune-dark.css b/packages/ui/certd-client/src/components/highlight-styles/atelier-dune-dark.css new file mode 100644 index 00000000..1684f522 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atelier-dune-dark.css @@ -0,0 +1,69 @@ +/* Base16 Atelier Dune Dark - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ + +/* Atelier-Dune Comment */ +.hljs-comment, +.hljs-quote { + color: #999580; +} + +/* Atelier-Dune Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #d73737; +} + +/* Atelier-Dune Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #b65611; +} + +/* Atelier-Dune Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #60ac39; +} + +/* Atelier-Dune Blue */ +.hljs-title, +.hljs-section { + color: #6684e1; +} + +/* Atelier-Dune Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #b854d4; +} + +.hljs { + display: block; + overflow-x: auto; + background: #20201d; + color: #a6a28c; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atelier-dune-light.css b/packages/ui/certd-client/src/components/highlight-styles/atelier-dune-light.css new file mode 100644 index 00000000..547719de --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atelier-dune-light.css @@ -0,0 +1,69 @@ +/* Base16 Atelier Dune Light - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/dune) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ + +/* Atelier-Dune Comment */ +.hljs-comment, +.hljs-quote { + color: #7d7a68; +} + +/* Atelier-Dune Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #d73737; +} + +/* Atelier-Dune Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #b65611; +} + +/* Atelier-Dune Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #60ac39; +} + +/* Atelier-Dune Blue */ +.hljs-title, +.hljs-section { + color: #6684e1; +} + +/* Atelier-Dune Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #b854d4; +} + +.hljs { + display: block; + overflow-x: auto; + background: #fefbec; + color: #6e6b5e; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atelier-estuary-dark.css b/packages/ui/certd-client/src/components/highlight-styles/atelier-estuary-dark.css new file mode 100644 index 00000000..a5e50718 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atelier-estuary-dark.css @@ -0,0 +1,84 @@ +/* Base16 Atelier Estuary Dark - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/estuary) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ + +/* Atelier-Estuary Comment */ +.hljs-comment, +.hljs-quote { + color: #878573; +} + +/* Atelier-Estuary Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #ba6236; +} + +/* Atelier-Estuary Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #ae7313; +} + +/* Atelier-Estuary Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #7d9726; +} + +/* Atelier-Estuary Blue */ +.hljs-title, +.hljs-section { + color: #36a166; +} + +/* Atelier-Estuary Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #5f9182; +} + +.hljs-deletion, +.hljs-addition { + color: #22221b; + display: inline-block; + width: 100%; +} + +.hljs-deletion { + background-color: #ba6236; +} + +.hljs-addition { + background-color: #7d9726; +} + +.hljs { + display: block; + overflow-x: auto; + background: #22221b; + color: #929181; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atelier-estuary-light.css b/packages/ui/certd-client/src/components/highlight-styles/atelier-estuary-light.css new file mode 100644 index 00000000..1daee5d9 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atelier-estuary-light.css @@ -0,0 +1,84 @@ +/* Base16 Atelier Estuary Light - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/estuary) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ + +/* Atelier-Estuary Comment */ +.hljs-comment, +.hljs-quote { + color: #6c6b5a; +} + +/* Atelier-Estuary Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #ba6236; +} + +/* Atelier-Estuary Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #ae7313; +} + +/* Atelier-Estuary Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #7d9726; +} + +/* Atelier-Estuary Blue */ +.hljs-title, +.hljs-section { + color: #36a166; +} + +/* Atelier-Estuary Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #5f9182; +} + +.hljs-deletion, +.hljs-addition { + color: #22221b; + display: inline-block; + width: 100%; +} + +.hljs-deletion { + background-color: #ba6236; +} + +.hljs-addition { + background-color: #7d9726; +} + +.hljs { + display: block; + overflow-x: auto; + background: #f4f3ec; + color: #5f5e4e; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atelier-forest-dark.css b/packages/ui/certd-client/src/components/highlight-styles/atelier-forest-dark.css new file mode 100644 index 00000000..0ef4fae3 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atelier-forest-dark.css @@ -0,0 +1,69 @@ +/* Base16 Atelier Forest Dark - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/forest) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ + +/* Atelier-Forest Comment */ +.hljs-comment, +.hljs-quote { + color: #9c9491; +} + +/* Atelier-Forest Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #f22c40; +} + +/* Atelier-Forest Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #df5320; +} + +/* Atelier-Forest Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #7b9726; +} + +/* Atelier-Forest Blue */ +.hljs-title, +.hljs-section { + color: #407ee7; +} + +/* Atelier-Forest Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #6666ea; +} + +.hljs { + display: block; + overflow-x: auto; + background: #1b1918; + color: #a8a19f; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atelier-forest-light.css b/packages/ui/certd-client/src/components/highlight-styles/atelier-forest-light.css new file mode 100644 index 00000000..bbedde18 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atelier-forest-light.css @@ -0,0 +1,69 @@ +/* Base16 Atelier Forest Light - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/forest) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ + +/* Atelier-Forest Comment */ +.hljs-comment, +.hljs-quote { + color: #766e6b; +} + +/* Atelier-Forest Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #f22c40; +} + +/* Atelier-Forest Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #df5320; +} + +/* Atelier-Forest Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #7b9726; +} + +/* Atelier-Forest Blue */ +.hljs-title, +.hljs-section { + color: #407ee7; +} + +/* Atelier-Forest Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #6666ea; +} + +.hljs { + display: block; + overflow-x: auto; + background: #f1efee; + color: #68615e; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atelier-heath-dark.css b/packages/ui/certd-client/src/components/highlight-styles/atelier-heath-dark.css new file mode 100644 index 00000000..fe01ff72 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atelier-heath-dark.css @@ -0,0 +1,69 @@ +/* Base16 Atelier Heath Dark - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/heath) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ + +/* Atelier-Heath Comment */ +.hljs-comment, +.hljs-quote { + color: #9e8f9e; +} + +/* Atelier-Heath Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #ca402b; +} + +/* Atelier-Heath Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #a65926; +} + +/* Atelier-Heath Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #918b3b; +} + +/* Atelier-Heath Blue */ +.hljs-title, +.hljs-section { + color: #516aec; +} + +/* Atelier-Heath Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #7b59c0; +} + +.hljs { + display: block; + overflow-x: auto; + background: #1b181b; + color: #ab9bab; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atelier-heath-light.css b/packages/ui/certd-client/src/components/highlight-styles/atelier-heath-light.css new file mode 100644 index 00000000..ee43786d --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atelier-heath-light.css @@ -0,0 +1,69 @@ +/* Base16 Atelier Heath Light - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/heath) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ + +/* Atelier-Heath Comment */ +.hljs-comment, +.hljs-quote { + color: #776977; +} + +/* Atelier-Heath Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #ca402b; +} + +/* Atelier-Heath Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #a65926; +} + +/* Atelier-Heath Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #918b3b; +} + +/* Atelier-Heath Blue */ +.hljs-title, +.hljs-section { + color: #516aec; +} + +/* Atelier-Heath Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #7b59c0; +} + +.hljs { + display: block; + overflow-x: auto; + background: #f7f3f7; + color: #695d69; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atelier-lakeside-dark.css b/packages/ui/certd-client/src/components/highlight-styles/atelier-lakeside-dark.css new file mode 100644 index 00000000..a937d3bf --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atelier-lakeside-dark.css @@ -0,0 +1,69 @@ +/* Base16 Atelier Lakeside Dark - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/lakeside) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ + +/* Atelier-Lakeside Comment */ +.hljs-comment, +.hljs-quote { + color: #7195a8; +} + +/* Atelier-Lakeside Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #d22d72; +} + +/* Atelier-Lakeside Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #935c25; +} + +/* Atelier-Lakeside Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #568c3b; +} + +/* Atelier-Lakeside Blue */ +.hljs-title, +.hljs-section { + color: #257fad; +} + +/* Atelier-Lakeside Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #6b6bb8; +} + +.hljs { + display: block; + overflow-x: auto; + background: #161b1d; + color: #7ea2b4; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atelier-lakeside-light.css b/packages/ui/certd-client/src/components/highlight-styles/atelier-lakeside-light.css new file mode 100644 index 00000000..6c7e8f9e --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atelier-lakeside-light.css @@ -0,0 +1,69 @@ +/* Base16 Atelier Lakeside Light - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/lakeside) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ + +/* Atelier-Lakeside Comment */ +.hljs-comment, +.hljs-quote { + color: #5a7b8c; +} + +/* Atelier-Lakeside Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #d22d72; +} + +/* Atelier-Lakeside Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #935c25; +} + +/* Atelier-Lakeside Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #568c3b; +} + +/* Atelier-Lakeside Blue */ +.hljs-title, +.hljs-section { + color: #257fad; +} + +/* Atelier-Lakeside Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #6b6bb8; +} + +.hljs { + display: block; + overflow-x: auto; + background: #ebf8ff; + color: #516d7b; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atelier-plateau-dark.css b/packages/ui/certd-client/src/components/highlight-styles/atelier-plateau-dark.css new file mode 100644 index 00000000..3bb05269 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atelier-plateau-dark.css @@ -0,0 +1,84 @@ +/* Base16 Atelier Plateau Dark - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/plateau) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ + +/* Atelier-Plateau Comment */ +.hljs-comment, +.hljs-quote { + color: #7e7777; +} + +/* Atelier-Plateau Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #ca4949; +} + +/* Atelier-Plateau Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #b45a3c; +} + +/* Atelier-Plateau Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #4b8b8b; +} + +/* Atelier-Plateau Blue */ +.hljs-title, +.hljs-section { + color: #7272ca; +} + +/* Atelier-Plateau Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #8464c4; +} + +.hljs-deletion, +.hljs-addition { + color: #1b1818; + display: inline-block; + width: 100%; +} + +.hljs-deletion { + background-color: #ca4949; +} + +.hljs-addition { + background-color: #4b8b8b; +} + +.hljs { + display: block; + overflow-x: auto; + background: #1b1818; + color: #8a8585; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atelier-plateau-light.css b/packages/ui/certd-client/src/components/highlight-styles/atelier-plateau-light.css new file mode 100644 index 00000000..5f0222be --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atelier-plateau-light.css @@ -0,0 +1,84 @@ +/* Base16 Atelier Plateau Light - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/plateau) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ + +/* Atelier-Plateau Comment */ +.hljs-comment, +.hljs-quote { + color: #655d5d; +} + +/* Atelier-Plateau Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #ca4949; +} + +/* Atelier-Plateau Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #b45a3c; +} + +/* Atelier-Plateau Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #4b8b8b; +} + +/* Atelier-Plateau Blue */ +.hljs-title, +.hljs-section { + color: #7272ca; +} + +/* Atelier-Plateau Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #8464c4; +} + +.hljs-deletion, +.hljs-addition { + color: #1b1818; + display: inline-block; + width: 100%; +} + +.hljs-deletion { + background-color: #ca4949; +} + +.hljs-addition { + background-color: #4b8b8b; +} + +.hljs { + display: block; + overflow-x: auto; + background: #f4ecec; + color: #585050; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atelier-savanna-dark.css b/packages/ui/certd-client/src/components/highlight-styles/atelier-savanna-dark.css new file mode 100644 index 00000000..38f83143 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atelier-savanna-dark.css @@ -0,0 +1,84 @@ +/* Base16 Atelier Savanna Dark - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/savanna) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ + +/* Atelier-Savanna Comment */ +.hljs-comment, +.hljs-quote { + color: #78877d; +} + +/* Atelier-Savanna Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #b16139; +} + +/* Atelier-Savanna Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #9f713c; +} + +/* Atelier-Savanna Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #489963; +} + +/* Atelier-Savanna Blue */ +.hljs-title, +.hljs-section { + color: #478c90; +} + +/* Atelier-Savanna Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #55859b; +} + +.hljs-deletion, +.hljs-addition { + color: #171c19; + display: inline-block; + width: 100%; +} + +.hljs-deletion { + background-color: #b16139; +} + +.hljs-addition { + background-color: #489963; +} + +.hljs { + display: block; + overflow-x: auto; + background: #171c19; + color: #87928a; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atelier-savanna-light.css b/packages/ui/certd-client/src/components/highlight-styles/atelier-savanna-light.css new file mode 100644 index 00000000..1ccd7c68 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atelier-savanna-light.css @@ -0,0 +1,84 @@ +/* Base16 Atelier Savanna Light - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/savanna) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ + +/* Atelier-Savanna Comment */ +.hljs-comment, +.hljs-quote { + color: #5f6d64; +} + +/* Atelier-Savanna Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #b16139; +} + +/* Atelier-Savanna Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #9f713c; +} + +/* Atelier-Savanna Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #489963; +} + +/* Atelier-Savanna Blue */ +.hljs-title, +.hljs-section { + color: #478c90; +} + +/* Atelier-Savanna Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #55859b; +} + +.hljs-deletion, +.hljs-addition { + color: #171c19; + display: inline-block; + width: 100%; +} + +.hljs-deletion { + background-color: #b16139; +} + +.hljs-addition { + background-color: #489963; +} + +.hljs { + display: block; + overflow-x: auto; + background: #ecf4ee; + color: #526057; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atelier-seaside-dark.css b/packages/ui/certd-client/src/components/highlight-styles/atelier-seaside-dark.css new file mode 100644 index 00000000..df29949c --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atelier-seaside-dark.css @@ -0,0 +1,69 @@ +/* Base16 Atelier Seaside Dark - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/seaside) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ + +/* Atelier-Seaside Comment */ +.hljs-comment, +.hljs-quote { + color: #809980; +} + +/* Atelier-Seaside Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #e6193c; +} + +/* Atelier-Seaside Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #87711d; +} + +/* Atelier-Seaside Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #29a329; +} + +/* Atelier-Seaside Blue */ +.hljs-title, +.hljs-section { + color: #3d62f5; +} + +/* Atelier-Seaside Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #ad2bee; +} + +.hljs { + display: block; + overflow-x: auto; + background: #131513; + color: #8ca68c; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atelier-seaside-light.css b/packages/ui/certd-client/src/components/highlight-styles/atelier-seaside-light.css new file mode 100644 index 00000000..9d960f29 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atelier-seaside-light.css @@ -0,0 +1,69 @@ +/* Base16 Atelier Seaside Light - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/seaside) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ + +/* Atelier-Seaside Comment */ +.hljs-comment, +.hljs-quote { + color: #687d68; +} + +/* Atelier-Seaside Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #e6193c; +} + +/* Atelier-Seaside Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #87711d; +} + +/* Atelier-Seaside Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #29a329; +} + +/* Atelier-Seaside Blue */ +.hljs-title, +.hljs-section { + color: #3d62f5; +} + +/* Atelier-Seaside Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #ad2bee; +} + +.hljs { + display: block; + overflow-x: auto; + background: #f4fbf4; + color: #5e6e5e; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atelier-sulphurpool-dark.css b/packages/ui/certd-client/src/components/highlight-styles/atelier-sulphurpool-dark.css new file mode 100644 index 00000000..c2ab7938 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atelier-sulphurpool-dark.css @@ -0,0 +1,69 @@ +/* Base16 Atelier Sulphurpool Dark - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/sulphurpool) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ + +/* Atelier-Sulphurpool Comment */ +.hljs-comment, +.hljs-quote { + color: #898ea4; +} + +/* Atelier-Sulphurpool Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #c94922; +} + +/* Atelier-Sulphurpool Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #c76b29; +} + +/* Atelier-Sulphurpool Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #ac9739; +} + +/* Atelier-Sulphurpool Blue */ +.hljs-title, +.hljs-section { + color: #3d8fd1; +} + +/* Atelier-Sulphurpool Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #6679cc; +} + +.hljs { + display: block; + overflow-x: auto; + background: #202746; + color: #979db4; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atelier-sulphurpool-light.css b/packages/ui/certd-client/src/components/highlight-styles/atelier-sulphurpool-light.css new file mode 100644 index 00000000..96c47d08 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atelier-sulphurpool-light.css @@ -0,0 +1,69 @@ +/* Base16 Atelier Sulphurpool Light - Theme */ +/* by Bram de Haan (http://atelierbram.github.io/syntax-highlighting/atelier-schemes/sulphurpool) */ +/* Original Base16 color scheme by Chris Kempson (https://github.com/chriskempson/base16) */ + +/* Atelier-Sulphurpool Comment */ +.hljs-comment, +.hljs-quote { + color: #6b7394; +} + +/* Atelier-Sulphurpool Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-regexp, +.hljs-link, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #c94922; +} + +/* Atelier-Sulphurpool Orange */ +.hljs-number, +.hljs-meta, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #c76b29; +} + +/* Atelier-Sulphurpool Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet { + color: #ac9739; +} + +/* Atelier-Sulphurpool Blue */ +.hljs-title, +.hljs-section { + color: #3d8fd1; +} + +/* Atelier-Sulphurpool Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #6679cc; +} + +.hljs { + display: block; + overflow-x: auto; + background: #f5f7ff; + color: #5e6687; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atom-one-dark.css b/packages/ui/certd-client/src/components/highlight-styles/atom-one-dark.css new file mode 100644 index 00000000..1616aafe --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atom-one-dark.css @@ -0,0 +1,96 @@ +/* + +Atom One Dark by Daniel Gamage +Original One Dark Syntax theme from https://github.com/atom/one-dark-syntax + +base: #282c34 +mono-1: #abb2bf +mono-2: #818896 +mono-3: #5c6370 +hue-1: #56b6c2 +hue-2: #61aeee +hue-3: #c678dd +hue-4: #98c379 +hue-5: #e06c75 +hue-5-2: #be5046 +hue-6: #d19a66 +hue-6-2: #e6c07b + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + color: #abb2bf; + background: #282c34; +} + +.hljs-comment, +.hljs-quote { + color: #5c6370; + font-style: italic; +} + +.hljs-doctag, +.hljs-keyword, +.hljs-formula { + color: #c678dd; +} + +.hljs-section, +.hljs-name, +.hljs-selector-tag, +.hljs-deletion, +.hljs-subst { + color: #e06c75; +} + +.hljs-literal { + color: #56b6c2; +} + +.hljs-string, +.hljs-regexp, +.hljs-addition, +.hljs-attribute, +.hljs-meta-string { + color: #98c379; +} + +.hljs-built_in, +.hljs-class .hljs-title { + color: #e6c07b; +} + +.hljs-attr, +.hljs-variable, +.hljs-template-variable, +.hljs-type, +.hljs-selector-class, +.hljs-selector-attr, +.hljs-selector-pseudo, +.hljs-number { + color: #d19a66; +} + +.hljs-symbol, +.hljs-bullet, +.hljs-link, +.hljs-meta, +.hljs-selector-id, +.hljs-title { + color: #61aeee; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} + +.hljs-link { + text-decoration: underline; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/atom-one-light.css b/packages/ui/certd-client/src/components/highlight-styles/atom-one-light.css new file mode 100644 index 00000000..d5bd1d2a --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/atom-one-light.css @@ -0,0 +1,96 @@ +/* + +Atom One Light by Daniel Gamage +Original One Light Syntax theme from https://github.com/atom/one-light-syntax + +base: #fafafa +mono-1: #383a42 +mono-2: #686b77 +mono-3: #a0a1a7 +hue-1: #0184bb +hue-2: #4078f2 +hue-3: #a626a4 +hue-4: #50a14f +hue-5: #e45649 +hue-5-2: #c91243 +hue-6: #986801 +hue-6-2: #c18401 + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + color: #383a42; + background: #fafafa; +} + +.hljs-comment, +.hljs-quote { + color: #a0a1a7; + font-style: italic; +} + +.hljs-doctag, +.hljs-keyword, +.hljs-formula { + color: #a626a4; +} + +.hljs-section, +.hljs-name, +.hljs-selector-tag, +.hljs-deletion, +.hljs-subst { + color: #e45649; +} + +.hljs-literal { + color: #0184bb; +} + +.hljs-string, +.hljs-regexp, +.hljs-addition, +.hljs-attribute, +.hljs-meta-string { + color: #50a14f; +} + +.hljs-built_in, +.hljs-class .hljs-title { + color: #c18401; +} + +.hljs-attr, +.hljs-variable, +.hljs-template-variable, +.hljs-type, +.hljs-selector-class, +.hljs-selector-attr, +.hljs-selector-pseudo, +.hljs-number { + color: #986801; +} + +.hljs-symbol, +.hljs-bullet, +.hljs-link, +.hljs-meta, +.hljs-selector-id, +.hljs-title { + color: #4078f2; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} + +.hljs-link { + text-decoration: underline; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/brown-paper.css b/packages/ui/certd-client/src/components/highlight-styles/brown-paper.css new file mode 100644 index 00000000..f0197b92 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/brown-paper.css @@ -0,0 +1,64 @@ +/* + +Brown Paper style from goldblog.com.ua (c) Zaripov Yura + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background:#b7a68e url(./brown-papersq.png); +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-literal { + color:#005599; + font-weight:bold; +} + +.hljs, +.hljs-subst { + color: #363c69; +} + +.hljs-string, +.hljs-title, +.hljs-section, +.hljs-type, +.hljs-attribute, +.hljs-symbol, +.hljs-bullet, +.hljs-built_in, +.hljs-addition, +.hljs-variable, +.hljs-template-tag, +.hljs-template-variable, +.hljs-link, +.hljs-name { + color: #2c009f; +} + +.hljs-comment, +.hljs-quote, +.hljs-meta, +.hljs-deletion { + color: #802022; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-literal, +.hljs-doctag, +.hljs-title, +.hljs-section, +.hljs-type, +.hljs-name, +.hljs-strong { + font-weight: bold; +} + +.hljs-emphasis { + font-style: italic; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/brown-papersq.png b/packages/ui/certd-client/src/components/highlight-styles/brown-papersq.png new file mode 100644 index 0000000000000000000000000000000000000000..3813903dbf9fa7b1fb5bd11d9534c06667d9056f GIT binary patch literal 18198 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
G3S-EN>9CM!{YB*|;6wg-K3V?)eR((z#1 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 literal 0 HcmV?d00001 diff --git a/packages/ui/certd-client/src/components/highlight-styles/codepen-embed.css b/packages/ui/certd-client/src/components/highlight-styles/codepen-embed.css new file mode 100644 index 00000000..195c4a07 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/codepen-embed.css @@ -0,0 +1,60 @@ +/* + codepen.io Embed Theme + Author: Justin Perry + Original theme - https://github.com/chriskempson/tomorrow-theme +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #222; + color: #fff; +} + +.hljs-comment, +.hljs-quote { + color: #777; +} + +.hljs-variable, +.hljs-template-variable, +.hljs-tag, +.hljs-regexp, +.hljs-meta, +.hljs-number, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-params, +.hljs-symbol, +.hljs-bullet, +.hljs-link, +.hljs-deletion { + color: #ab875d; +} + +.hljs-section, +.hljs-title, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class, +.hljs-type, +.hljs-attribute { + color: #9b869b; +} + +.hljs-string, +.hljs-keyword, +.hljs-selector-tag, +.hljs-addition { + color: #8f9c6c; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/color-brewer.css b/packages/ui/certd-client/src/components/highlight-styles/color-brewer.css new file mode 100644 index 00000000..7934d986 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/color-brewer.css @@ -0,0 +1,71 @@ +/* + +Colorbrewer theme +Original: https://github.com/mbostock/colorbrewer-theme (c) Mike Bostock +Ported by Fabrício Tavares de Oliveira + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #fff; +} + +.hljs, +.hljs-subst { + color: #000; +} + +.hljs-string, +.hljs-meta, +.hljs-symbol, +.hljs-template-tag, +.hljs-template-variable, +.hljs-addition { + color: #756bb1; +} + +.hljs-comment, +.hljs-quote { + color: #636363; +} + +.hljs-number, +.hljs-regexp, +.hljs-literal, +.hljs-bullet, +.hljs-link { + color: #31a354; +} + +.hljs-deletion, +.hljs-variable { + color: #88f; +} + + + +.hljs-keyword, +.hljs-selector-tag, +.hljs-title, +.hljs-section, +.hljs-built_in, +.hljs-doctag, +.hljs-type, +.hljs-tag, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class, +.hljs-strong { + color: #3182bd; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-attribute { + color: #e6550d; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/darcula.css b/packages/ui/certd-client/src/components/highlight-styles/darcula.css new file mode 100644 index 00000000..be182d0b --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/darcula.css @@ -0,0 +1,77 @@ +/* + +Darcula color scheme from the JetBrains family of IDEs + +*/ + + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #2b2b2b; +} + +.hljs { + color: #bababa; +} + +.hljs-strong, +.hljs-emphasis { + color: #a8a8a2; +} + +.hljs-bullet, +.hljs-quote, +.hljs-link, +.hljs-number, +.hljs-regexp, +.hljs-literal { + color: #6896ba; +} + +.hljs-code, +.hljs-selector-class { + color: #a6e22e; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-section, +.hljs-attribute, +.hljs-name, +.hljs-variable { + color: #cb7832; +} + +.hljs-params { + color: #b9b9b9; +} + +.hljs-string { + color: #6a8759; +} + +.hljs-subst, +.hljs-type, +.hljs-built_in, +.hljs-builtin-name, +.hljs-symbol, +.hljs-selector-id, +.hljs-selector-attr, +.hljs-selector-pseudo, +.hljs-template-tag, +.hljs-template-variable, +.hljs-addition { + color: #e0c46c; +} + +.hljs-comment, +.hljs-deletion, +.hljs-meta { + color: #7f7f7f; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/dark.css b/packages/ui/certd-client/src/components/highlight-styles/dark.css new file mode 100644 index 00000000..b4724f5f --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/dark.css @@ -0,0 +1,63 @@ +/* + +Dark style from softwaremaniacs.org (c) Ivan Sagalaev + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #444; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-literal, +.hljs-section, +.hljs-link { + color: white; +} + +.hljs, +.hljs-subst { + color: #ddd; +} + +.hljs-string, +.hljs-title, +.hljs-name, +.hljs-type, +.hljs-attribute, +.hljs-symbol, +.hljs-bullet, +.hljs-built_in, +.hljs-addition, +.hljs-variable, +.hljs-template-tag, +.hljs-template-variable { + color: #d88; +} + +.hljs-comment, +.hljs-quote, +.hljs-deletion, +.hljs-meta { + color: #777; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-literal, +.hljs-title, +.hljs-section, +.hljs-doctag, +.hljs-type, +.hljs-name, +.hljs-strong { + font-weight: bold; +} + +.hljs-emphasis { + font-style: italic; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/darkula.css b/packages/ui/certd-client/src/components/highlight-styles/darkula.css new file mode 100644 index 00000000..f4646c3c --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/darkula.css @@ -0,0 +1,6 @@ +/* + Deprecated due to a typo in the name and left here for compatibility purpose only. + Please use darcula.css instead. +*/ + +@import url('darcula.css'); diff --git a/packages/ui/certd-client/src/components/highlight-styles/default.css b/packages/ui/certd-client/src/components/highlight-styles/default.css new file mode 100644 index 00000000..f1bfade3 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/default.css @@ -0,0 +1,99 @@ +/* + +Original highlight.js style (c) Ivan Sagalaev + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #F0F0F0; +} + + +/* Base color: saturation 0; */ + +.hljs, +.hljs-subst { + color: #444; +} + +.hljs-comment { + color: #888888; +} + +.hljs-keyword, +.hljs-attribute, +.hljs-selector-tag, +.hljs-meta-keyword, +.hljs-doctag, +.hljs-name { + font-weight: bold; +} + + +/* User color: hue: 0 */ + +.hljs-type, +.hljs-string, +.hljs-number, +.hljs-selector-id, +.hljs-selector-class, +.hljs-quote, +.hljs-template-tag, +.hljs-deletion { + color: #880000; +} + +.hljs-title, +.hljs-section { + color: #880000; + font-weight: bold; +} + +.hljs-regexp, +.hljs-symbol, +.hljs-variable, +.hljs-template-variable, +.hljs-link, +.hljs-selector-attr, +.hljs-selector-pseudo { + color: #BC6060; +} + + +/* Language color: hue: 90; */ + +.hljs-literal { + color: #78A960; +} + +.hljs-built_in, +.hljs-bullet, +.hljs-code, +.hljs-addition { + color: #397300; +} + + +/* Meta color: hue: 200 */ + +.hljs-meta { + color: #1f7199; +} + +.hljs-meta-string { + color: #4d99bf; +} + + +/* Misc effects */ + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/docco.css b/packages/ui/certd-client/src/components/highlight-styles/docco.css new file mode 100644 index 00000000..db366be3 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/docco.css @@ -0,0 +1,97 @@ +/* +Docco style used in http://jashkenas.github.com/docco/ converted by Simon Madine (@thingsinjars) +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + color: #000; + background: #f8f8ff; +} + +.hljs-comment, +.hljs-quote { + color: #408080; + font-style: italic; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-literal, +.hljs-subst { + color: #954121; +} + +.hljs-number { + color: #40a070; +} + +.hljs-string, +.hljs-doctag { + color: #219161; +} + +.hljs-selector-id, +.hljs-selector-class, +.hljs-section, +.hljs-type { + color: #19469d; +} + +.hljs-params { + color: #00f; +} + +.hljs-title { + color: #458; + font-weight: bold; +} + +.hljs-tag, +.hljs-name, +.hljs-attribute { + color: #000080; + font-weight: normal; +} + +.hljs-variable, +.hljs-template-variable { + color: #008080; +} + +.hljs-regexp, +.hljs-link { + color: #b68; +} + +.hljs-symbol, +.hljs-bullet { + color: #990073; +} + +.hljs-built_in, +.hljs-builtin-name { + color: #0086b3; +} + +.hljs-meta { + color: #999; + font-weight: bold; +} + +.hljs-deletion { + background: #fdd; +} + +.hljs-addition { + background: #dfd; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/dracula.css b/packages/ui/certd-client/src/components/highlight-styles/dracula.css new file mode 100644 index 00000000..d591db68 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/dracula.css @@ -0,0 +1,76 @@ +/* + +Dracula Theme v1.2.0 + +https://github.com/zenorocha/dracula-theme + +Copyright 2015, All rights reserved + +Code licensed under the MIT license +http://zenorocha.mit-license.org + +@author Éverton Ribeiro +@author Zeno Rocha + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #282a36; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-literal, +.hljs-section, +.hljs-link { + color: #8be9fd; +} + +.hljs-function .hljs-keyword { + color: #ff79c6; +} + +.hljs, +.hljs-subst { + color: #f8f8f2; +} + +.hljs-string, +.hljs-title, +.hljs-name, +.hljs-type, +.hljs-attribute, +.hljs-symbol, +.hljs-bullet, +.hljs-addition, +.hljs-variable, +.hljs-template-tag, +.hljs-template-variable { + color: #f1fa8c; +} + +.hljs-comment, +.hljs-quote, +.hljs-deletion, +.hljs-meta { + color: #6272a4; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-literal, +.hljs-title, +.hljs-section, +.hljs-doctag, +.hljs-type, +.hljs-name, +.hljs-strong { + font-weight: bold; +} + +.hljs-emphasis { + font-style: italic; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/far.css b/packages/ui/certd-client/src/components/highlight-styles/far.css new file mode 100644 index 00000000..2b3f87b5 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/far.css @@ -0,0 +1,71 @@ +/* + +FAR Style (c) MajestiC + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #000080; +} + +.hljs, +.hljs-subst { + color: #0ff; +} + +.hljs-string, +.hljs-attribute, +.hljs-symbol, +.hljs-bullet, +.hljs-built_in, +.hljs-builtin-name, +.hljs-template-tag, +.hljs-template-variable, +.hljs-addition { + color: #ff0; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-section, +.hljs-type, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class, +.hljs-variable { + color: #fff; +} + +.hljs-comment, +.hljs-quote, +.hljs-doctag, +.hljs-deletion { + color: #888; +} + +.hljs-number, +.hljs-regexp, +.hljs-literal, +.hljs-link { + color: #0f0; +} + +.hljs-meta { + color: #008080; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-title, +.hljs-section, +.hljs-name, +.hljs-strong { + font-weight: bold; +} + +.hljs-emphasis { + font-style: italic; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/foundation.css b/packages/ui/certd-client/src/components/highlight-styles/foundation.css new file mode 100644 index 00000000..f1fe64b3 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/foundation.css @@ -0,0 +1,88 @@ +/* +Description: Foundation 4 docs style for highlight.js +Author: Dan Allen +Website: http://foundation.zurb.com/docs/ +Version: 1.0 +Date: 2013-04-02 +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #eee; color: black; +} + +.hljs-link, +.hljs-emphasis, +.hljs-attribute, +.hljs-addition { + color: #070; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong, +.hljs-string, +.hljs-deletion { + color: #d14; +} + +.hljs-strong { + font-weight: bold; +} + +.hljs-quote, +.hljs-comment { + color: #998; + font-style: italic; +} + +.hljs-section, +.hljs-title { + color: #900; +} + +.hljs-class .hljs-title, +.hljs-type { + color: #458; +} + +.hljs-variable, +.hljs-template-variable { + color: #336699; +} + +.hljs-bullet { + color: #997700; +} + +.hljs-meta { + color: #3344bb; +} + +.hljs-code, +.hljs-number, +.hljs-literal, +.hljs-keyword, +.hljs-selector-tag { + color: #099; +} + +.hljs-regexp { + background-color: #fff0ff; + color: #880088; +} + +.hljs-symbol { + color: #990073; +} + +.hljs-tag, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #007700; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/github-gist.css b/packages/ui/certd-client/src/components/highlight-styles/github-gist.css new file mode 100644 index 00000000..155f0b91 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/github-gist.css @@ -0,0 +1,71 @@ +/** + * GitHub Gist Theme + * Author : Louis Barranqueiro - https://github.com/LouisBarranqueiro + */ + +.hljs { + display: block; + background: white; + padding: 0.5em; + color: #333333; + overflow-x: auto; +} + +.hljs-comment, +.hljs-meta { + color: #969896; +} + +.hljs-string, +.hljs-variable, +.hljs-template-variable, +.hljs-strong, +.hljs-emphasis, +.hljs-quote { + color: #df5000; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-type { + color: #a71d5d; +} + +.hljs-literal, +.hljs-symbol, +.hljs-bullet, +.hljs-attribute { + color: #0086b3; +} + +.hljs-section, +.hljs-name { + color: #63a35c; +} + +.hljs-tag { + color: #333333; +} + +.hljs-title, +.hljs-attr, +.hljs-selector-id, +.hljs-selector-class, +.hljs-selector-attr, +.hljs-selector-pseudo { + color: #795da3; +} + +.hljs-addition { + color: #55a532; + background-color: #eaffea; +} + +.hljs-deletion { + color: #bd2c00; + background-color: #ffecec; +} + +.hljs-link { + text-decoration: underline; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/github.css b/packages/ui/certd-client/src/components/highlight-styles/github.css new file mode 100644 index 00000000..791932b8 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/github.css @@ -0,0 +1,99 @@ +/* + +github.com style (c) Vasily Polovnyov + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + color: #333; + background: #f8f8f8; +} + +.hljs-comment, +.hljs-quote { + color: #998; + font-style: italic; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-subst { + color: #333; + font-weight: bold; +} + +.hljs-number, +.hljs-literal, +.hljs-variable, +.hljs-template-variable, +.hljs-tag .hljs-attr { + color: #008080; +} + +.hljs-string, +.hljs-doctag { + color: #d14; +} + +.hljs-title, +.hljs-section, +.hljs-selector-id { + color: #900; + font-weight: bold; +} + +.hljs-subst { + font-weight: normal; +} + +.hljs-type, +.hljs-class .hljs-title { + color: #458; + font-weight: bold; +} + +.hljs-tag, +.hljs-name, +.hljs-attribute { + color: #000080; + font-weight: normal; +} + +.hljs-regexp, +.hljs-link { + color: #009926; +} + +.hljs-symbol, +.hljs-bullet { + color: #990073; +} + +.hljs-built_in, +.hljs-builtin-name { + color: #0086b3; +} + +.hljs-meta { + color: #999; + font-weight: bold; +} + +.hljs-deletion { + background: #fdd; +} + +.hljs-addition { + background: #dfd; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/googlecode.css b/packages/ui/certd-client/src/components/highlight-styles/googlecode.css new file mode 100644 index 00000000..884ad635 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/googlecode.css @@ -0,0 +1,89 @@ +/* + +Google Code style (c) Aahan Krish + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: white; + color: black; +} + +.hljs-comment, +.hljs-quote { + color: #800; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-section, +.hljs-title, +.hljs-name { + color: #008; +} + +.hljs-variable, +.hljs-template-variable { + color: #660; +} + +.hljs-string, +.hljs-selector-attr, +.hljs-selector-pseudo, +.hljs-regexp { + color: #080; +} + +.hljs-literal, +.hljs-symbol, +.hljs-bullet, +.hljs-meta, +.hljs-number, +.hljs-link { + color: #066; +} + +.hljs-title, +.hljs-doctag, +.hljs-type, +.hljs-attr, +.hljs-built_in, +.hljs-builtin-name, +.hljs-params { + color: #606; +} + +.hljs-attribute, +.hljs-subst { + color: #000; +} + +.hljs-formula { + background-color: #eee; + font-style: italic; +} + +.hljs-selector-id, +.hljs-selector-class { + color: #9B703F +} + +.hljs-addition { + background-color: #baeeba; +} + +.hljs-deletion { + background-color: #ffc8bd; +} + +.hljs-doctag, +.hljs-strong { + font-weight: bold; +} + +.hljs-emphasis { + font-style: italic; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/grayscale.css b/packages/ui/certd-client/src/components/highlight-styles/grayscale.css new file mode 100644 index 00000000..5376f340 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/grayscale.css @@ -0,0 +1,101 @@ +/* + +grayscale style (c) MY Sun + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + color: #333; + background: #fff; +} + +.hljs-comment, +.hljs-quote { + color: #777; + font-style: italic; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-subst { + color: #333; + font-weight: bold; +} + +.hljs-number, +.hljs-literal { + color: #777; +} + +.hljs-string, +.hljs-doctag, +.hljs-formula { + color: #333; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAJ0lEQVQIW2O8e/fufwYGBgZBQUEQxcCIIfDu3Tuwivfv30NUoAsAALHpFMMLqZlPAAAAAElFTkSuQmCC) repeat; +} + +.hljs-title, +.hljs-section, +.hljs-selector-id { + color: #000; + font-weight: bold; +} + +.hljs-subst { + font-weight: normal; +} + +.hljs-class .hljs-title, +.hljs-type, +.hljs-name { + color: #333; + font-weight: bold; +} + +.hljs-tag { + color: #333; +} + +.hljs-regexp { + color: #333; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAICAYAAADA+m62AAAAPUlEQVQYV2NkQAN37979r6yszIgujiIAU4RNMVwhuiQ6H6wQl3XI4oy4FMHcCJPHcDS6J2A2EqUQpJhohQDexSef15DBCwAAAABJRU5ErkJggg==) repeat; +} + +.hljs-symbol, +.hljs-bullet, +.hljs-link { + color: #000; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAKElEQVQIW2NkQAO7d+/+z4gsBhJwdXVlhAvCBECKwIIwAbhKZBUwBQA6hBpm5efZsgAAAABJRU5ErkJggg==) repeat; +} + +.hljs-built_in, +.hljs-builtin-name { + color: #000; + text-decoration: underline; +} + +.hljs-meta { + color: #999; + font-weight: bold; +} + +.hljs-deletion { + color: #fff; + background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAADCAYAAABS3WWCAAAAE0lEQVQIW2MMDQ39zzhz5kwIAQAyxweWgUHd1AAAAABJRU5ErkJggg==) repeat; +} + +.hljs-addition { + color: #000; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAALUlEQVQYV2N89+7dfwYk8P79ewZBQUFkIQZGOiu6e/cuiptQHAPl0NtNxAQBAM97Oejj3Dg7AAAAAElFTkSuQmCC) repeat; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/gruvbox-dark.css b/packages/ui/certd-client/src/components/highlight-styles/gruvbox-dark.css new file mode 100644 index 00000000..f563811a --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/gruvbox-dark.css @@ -0,0 +1,108 @@ +/* + +Gruvbox style (dark) (c) Pavel Pertsev (original style at https://github.com/morhetz/gruvbox) + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #282828; +} + +.hljs, +.hljs-subst { + color: #ebdbb2; +} + +/* Gruvbox Red */ +.hljs-deletion, +.hljs-formula, +.hljs-keyword, +.hljs-link, +.hljs-selector-tag { + color: #fb4934; +} + +/* Gruvbox Blue */ +.hljs-built_in, +.hljs-emphasis, +.hljs-name, +.hljs-quote, +.hljs-strong, +.hljs-title, +.hljs-variable { + color: #83a598; +} + +/* Gruvbox Yellow */ +.hljs-attr, +.hljs-params, +.hljs-template-tag, +.hljs-type { + color: #fabd2f; +} + +/* Gruvbox Purple */ +.hljs-builtin-name, +.hljs-doctag, +.hljs-literal, +.hljs-number { + color: #8f3f71; +} + +/* Gruvbox Orange */ +.hljs-code, +.hljs-meta, +.hljs-regexp, +.hljs-selector-id, +.hljs-template-variable { + color: #fe8019; +} + +/* Gruvbox Green */ +.hljs-addition, +.hljs-meta-string, +.hljs-section, +.hljs-selector-attr, +.hljs-selector-class, +.hljs-string, +.hljs-symbol { + color: #b8bb26; +} + +/* Gruvbox Aqua */ +.hljs-attribute, +.hljs-bullet, +.hljs-class, +.hljs-function, +.hljs-function .hljs-keyword, +.hljs-meta-keyword, +.hljs-selector-pseudo, +.hljs-tag { + color: #8ec07c; +} + +/* Gruvbox Gray */ +.hljs-comment { + color: #928374; +} + +/* Gruvbox Purple */ +.hljs-link_label, +.hljs-literal, +.hljs-number { + color: #d3869b; +} + +.hljs-comment, +.hljs-emphasis { + font-style: italic; +} + +.hljs-section, +.hljs-strong, +.hljs-tag { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/gruvbox-light.css b/packages/ui/certd-client/src/components/highlight-styles/gruvbox-light.css new file mode 100644 index 00000000..ff45468e --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/gruvbox-light.css @@ -0,0 +1,108 @@ +/* + +Gruvbox style (light) (c) Pavel Pertsev (original style at https://github.com/morhetz/gruvbox) + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #fbf1c7; +} + +.hljs, +.hljs-subst { + color: #3c3836; +} + +/* Gruvbox Red */ +.hljs-deletion, +.hljs-formula, +.hljs-keyword, +.hljs-link, +.hljs-selector-tag { + color: #9d0006; +} + +/* Gruvbox Blue */ +.hljs-built_in, +.hljs-emphasis, +.hljs-name, +.hljs-quote, +.hljs-strong, +.hljs-title, +.hljs-variable { + color: #076678; +} + +/* Gruvbox Yellow */ +.hljs-attr, +.hljs-params, +.hljs-template-tag, +.hljs-type { + color: #b57614; +} + +/* Gruvbox Purple */ +.hljs-builtin-name, +.hljs-doctag, +.hljs-literal, +.hljs-number { + color: #8f3f71; +} + +/* Gruvbox Orange */ +.hljs-code, +.hljs-meta, +.hljs-regexp, +.hljs-selector-id, +.hljs-template-variable { + color: #af3a03; +} + +/* Gruvbox Green */ +.hljs-addition, +.hljs-meta-string, +.hljs-section, +.hljs-selector-attr, +.hljs-selector-class, +.hljs-string, +.hljs-symbol { + color: #79740e; +} + +/* Gruvbox Aqua */ +.hljs-attribute, +.hljs-bullet, +.hljs-class, +.hljs-function, +.hljs-function .hljs-keyword, +.hljs-meta-keyword, +.hljs-selector-pseudo, +.hljs-tag { + color: #427b58; +} + +/* Gruvbox Gray */ +.hljs-comment { + color: #928374; +} + +/* Gruvbox Purple */ +.hljs-link_label, +.hljs-literal, +.hljs-number { + color: #8f3f71; +} + +.hljs-comment, +.hljs-emphasis { + font-style: italic; +} + +.hljs-section, +.hljs-strong, +.hljs-tag { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/hopscotch.css b/packages/ui/certd-client/src/components/highlight-styles/hopscotch.css new file mode 100644 index 00000000..32e60d23 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/hopscotch.css @@ -0,0 +1,83 @@ +/* + * Hopscotch + * by Jan T. Sott + * https://github.com/idleberg/Hopscotch + * + * This work is licensed under the Creative Commons CC0 1.0 Universal License + */ + +/* Comment */ +.hljs-comment, +.hljs-quote { + color: #989498; +} + +/* Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-attribute, +.hljs-tag, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class, +.hljs-regexp, +.hljs-link, +.hljs-deletion { + color: #dd464c; +} + +/* Orange */ +.hljs-number, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params { + color: #fd8b19; +} + +/* Yellow */ +.hljs-class .hljs-title { + color: #fdcc59; +} + +/* Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet, +.hljs-addition { + color: #8fc13e; +} + +/* Aqua */ +.hljs-meta { + color: #149b93; +} + +/* Blue */ +.hljs-function, +.hljs-section, +.hljs-title { + color: #1290bf; +} + +/* Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #c85e7c; +} + +.hljs { + display: block; + background: #322931; + color: #b9b5b8; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/hybrid.css b/packages/ui/certd-client/src/components/highlight-styles/hybrid.css new file mode 100644 index 00000000..29735a18 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/hybrid.css @@ -0,0 +1,102 @@ +/* + +vim-hybrid theme by w0ng (https://github.com/w0ng/vim-hybrid) + +*/ + +/*background color*/ +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #1d1f21; +} + +/*selection color*/ +.hljs::selection, +.hljs span::selection { + background: #373b41; +} + +.hljs::-moz-selection, +.hljs span::-moz-selection { + background: #373b41; +} + +/*foreground color*/ +.hljs { + color: #c5c8c6; +} + +/*color: fg_yellow*/ +.hljs-title, +.hljs-name { + color: #f0c674; +} + +/*color: fg_comment*/ +.hljs-comment, +.hljs-meta, +.hljs-meta .hljs-keyword { + color: #707880; +} + +/*color: fg_red*/ +.hljs-number, +.hljs-symbol, +.hljs-literal, +.hljs-deletion, +.hljs-link { + color: #cc6666 +} + +/*color: fg_green*/ +.hljs-string, +.hljs-doctag, +.hljs-addition, +.hljs-regexp, +.hljs-selector-attr, +.hljs-selector-pseudo { + color: #b5bd68; +} + +/*color: fg_purple*/ +.hljs-attribute, +.hljs-code, +.hljs-selector-id { + color: #b294bb; +} + +/*color: fg_blue*/ +.hljs-keyword, +.hljs-selector-tag, +.hljs-bullet, +.hljs-tag { + color: #81a2be; +} + +/*color: fg_aqua*/ +.hljs-subst, +.hljs-variable, +.hljs-template-tag, +.hljs-template-variable { + color: #8abeb7; +} + +/*color: fg_orange*/ +.hljs-type, +.hljs-built_in, +.hljs-builtin-name, +.hljs-quote, +.hljs-section, +.hljs-selector-class { + color: #de935f; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/idea.css b/packages/ui/certd-client/src/components/highlight-styles/idea.css new file mode 100644 index 00000000..3bf1892b --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/idea.css @@ -0,0 +1,97 @@ +/* + +Intellij Idea-like styling (c) Vasily Polovnyov + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + color: #000; + background: #fff; +} + +.hljs-subst, +.hljs-title { + font-weight: normal; + color: #000; +} + +.hljs-comment, +.hljs-quote { + color: #808080; + font-style: italic; +} + +.hljs-meta { + color: #808000; +} + +.hljs-tag { + background: #efefef; +} + +.hljs-section, +.hljs-name, +.hljs-literal, +.hljs-keyword, +.hljs-selector-tag, +.hljs-type, +.hljs-selector-id, +.hljs-selector-class { + font-weight: bold; + color: #000080; +} + +.hljs-attribute, +.hljs-number, +.hljs-regexp, +.hljs-link { + font-weight: bold; + color: #0000ff; +} + +.hljs-number, +.hljs-regexp, +.hljs-link { + font-weight: normal; +} + +.hljs-string { + color: #008000; + font-weight: bold; +} + +.hljs-symbol, +.hljs-bullet, +.hljs-formula { + color: #000; + background: #d0eded; + font-style: italic; +} + +.hljs-doctag { + text-decoration: underline; +} + +.hljs-variable, +.hljs-template-variable { + color: #660e7a; +} + +.hljs-addition { + background: #baeeba; +} + +.hljs-deletion { + background: #ffc8bd; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/ir-black.css b/packages/ui/certd-client/src/components/highlight-styles/ir-black.css new file mode 100644 index 00000000..bd4c755e --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/ir-black.css @@ -0,0 +1,73 @@ +/* + IR_Black style (c) Vasily Mikhailitchenko +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #000; + color: #f8f8f8; +} + +.hljs-comment, +.hljs-quote, +.hljs-meta { + color: #7c7c7c; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-tag, +.hljs-name { + color: #96cbfe; +} + +.hljs-attribute, +.hljs-selector-id { + color: #ffffb6; +} + +.hljs-string, +.hljs-selector-attr, +.hljs-selector-pseudo, +.hljs-addition { + color: #a8ff60; +} + +.hljs-subst { + color: #daefa3; +} + +.hljs-regexp, +.hljs-link { + color: #e9c062; +} + +.hljs-title, +.hljs-section, +.hljs-type, +.hljs-doctag { + color: #ffffb6; +} + +.hljs-symbol, +.hljs-bullet, +.hljs-variable, +.hljs-template-variable, +.hljs-literal { + color: #c6c5fe; +} + +.hljs-number, +.hljs-deletion { + color:#ff73fd; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/kimbie.dark.css b/packages/ui/certd-client/src/components/highlight-styles/kimbie.dark.css new file mode 100644 index 00000000..d139cb5d --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/kimbie.dark.css @@ -0,0 +1,74 @@ +/* + Name: Kimbie (dark) + Author: Jan T. Sott + License: Creative Commons Attribution-ShareAlike 4.0 Unported License + URL: https://github.com/idleberg/Kimbie-highlight.js +*/ + +/* Kimbie Comment */ +.hljs-comment, +.hljs-quote { + color: #d6baad; +} + +/* Kimbie Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-tag, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class, +.hljs-regexp, +.hljs-meta { + color: #dc3958; +} + +/* Kimbie Orange */ +.hljs-number, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params, +.hljs-deletion, +.hljs-link { + color: #f79a32; +} + +/* Kimbie Yellow */ +.hljs-title, +.hljs-section, +.hljs-attribute { + color: #f06431; +} + +/* Kimbie Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet, +.hljs-addition { + color: #889b4a; +} + +/* Kimbie Purple */ +.hljs-keyword, +.hljs-selector-tag, +.hljs-function { + color: #98676a; +} + +.hljs { + display: block; + overflow-x: auto; + background: #221a0f; + color: #d3af86; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/kimbie.light.css b/packages/ui/certd-client/src/components/highlight-styles/kimbie.light.css new file mode 100644 index 00000000..04ff6ed3 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/kimbie.light.css @@ -0,0 +1,74 @@ +/* + Name: Kimbie (light) + Author: Jan T. Sott + License: Creative Commons Attribution-ShareAlike 4.0 Unported License + URL: https://github.com/idleberg/Kimbie-highlight.js +*/ + +/* Kimbie Comment */ +.hljs-comment, +.hljs-quote { + color: #a57a4c; +} + +/* Kimbie Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-tag, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class, +.hljs-regexp, +.hljs-meta { + color: #dc3958; +} + +/* Kimbie Orange */ +.hljs-number, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params, +.hljs-deletion, +.hljs-link { + color: #f79a32; +} + +/* Kimbie Yellow */ +.hljs-title, +.hljs-section, +.hljs-attribute { + color: #f06431; +} + +/* Kimbie Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet, +.hljs-addition { + color: #889b4a; +} + +/* Kimbie Purple */ +.hljs-keyword, +.hljs-selector-tag, +.hljs-function { + color: #98676a; +} + +.hljs { + display: block; + overflow-x: auto; + background: #fbebd4; + color: #84613d; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/magula.css b/packages/ui/certd-client/src/components/highlight-styles/magula.css new file mode 100644 index 00000000..44dee5e8 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/magula.css @@ -0,0 +1,70 @@ +/* +Description: Magula style for highligh.js +Author: Ruslan Keba +Website: http://rukeba.com/ +Version: 1.0 +Date: 2009-01-03 +Music: Aphex Twin / Xtal +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background-color: #f4f4f4; +} + +.hljs, +.hljs-subst { + color: black; +} + +.hljs-string, +.hljs-title, +.hljs-symbol, +.hljs-bullet, +.hljs-attribute, +.hljs-addition, +.hljs-variable, +.hljs-template-tag, +.hljs-template-variable { + color: #050; +} + +.hljs-comment, +.hljs-quote { + color: #777; +} + +.hljs-number, +.hljs-regexp, +.hljs-literal, +.hljs-type, +.hljs-link { + color: #800; +} + +.hljs-deletion, +.hljs-meta { + color: #00e; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-doctag, +.hljs-title, +.hljs-section, +.hljs-built_in, +.hljs-tag, +.hljs-name { + font-weight: bold; + color: navy; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/mono-blue.css b/packages/ui/certd-client/src/components/highlight-styles/mono-blue.css new file mode 100644 index 00000000..884c97c7 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/mono-blue.css @@ -0,0 +1,59 @@ +/* + Five-color theme from a single blue hue. +*/ +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #eaeef3; +} + +.hljs { + color: #00193a; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-title, +.hljs-section, +.hljs-doctag, +.hljs-name, +.hljs-strong { + font-weight: bold; +} + +.hljs-comment { + color: #738191; +} + +.hljs-string, +.hljs-title, +.hljs-section, +.hljs-built_in, +.hljs-literal, +.hljs-type, +.hljs-addition, +.hljs-tag, +.hljs-quote, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #0048ab; +} + +.hljs-meta, +.hljs-subst, +.hljs-symbol, +.hljs-regexp, +.hljs-attribute, +.hljs-deletion, +.hljs-variable, +.hljs-template-variable, +.hljs-link, +.hljs-bullet { + color: #4c81c9; +} + +.hljs-emphasis { + font-style: italic; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/monokai-sublime.css b/packages/ui/certd-client/src/components/highlight-styles/monokai-sublime.css new file mode 100644 index 00000000..2864170d --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/monokai-sublime.css @@ -0,0 +1,83 @@ +/* + +Monokai Sublime style. Derived from Monokai by noformnocontent http://nn.mit-license.org/ + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #23241f; +} + +.hljs, +.hljs-tag, +.hljs-subst { + color: #f8f8f2; +} + +.hljs-strong, +.hljs-emphasis { + color: #a8a8a2; +} + +.hljs-bullet, +.hljs-quote, +.hljs-number, +.hljs-regexp, +.hljs-literal, +.hljs-link { + color: #ae81ff; +} + +.hljs-code, +.hljs-title, +.hljs-section, +.hljs-selector-class { + color: #a6e22e; +} + +.hljs-strong { + font-weight: bold; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-name, +.hljs-attr { + color: #f92672; +} + +.hljs-symbol, +.hljs-attribute { + color: #66d9ef; +} + +.hljs-params, +.hljs-class .hljs-title { + color: #f8f8f2; +} + +.hljs-string, +.hljs-type, +.hljs-built_in, +.hljs-builtin-name, +.hljs-selector-id, +.hljs-selector-attr, +.hljs-selector-pseudo, +.hljs-addition, +.hljs-variable, +.hljs-template-variable { + color: #e6db74; +} + +.hljs-comment, +.hljs-deletion, +.hljs-meta { + color: #75715e; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/monokai.css b/packages/ui/certd-client/src/components/highlight-styles/monokai.css new file mode 100644 index 00000000..775d53f9 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/monokai.css @@ -0,0 +1,70 @@ +/* +Monokai style - ported by Luigi Maselli - http://grigio.org +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #272822; color: #ddd; +} + +.hljs-tag, +.hljs-keyword, +.hljs-selector-tag, +.hljs-literal, +.hljs-strong, +.hljs-name { + color: #f92672; +} + +.hljs-code { + color: #66d9ef; +} + +.hljs-class .hljs-title { + color: white; +} + +.hljs-attribute, +.hljs-symbol, +.hljs-regexp, +.hljs-link { + color: #bf79db; +} + +.hljs-string, +.hljs-bullet, +.hljs-subst, +.hljs-title, +.hljs-section, +.hljs-emphasis, +.hljs-type, +.hljs-built_in, +.hljs-builtin-name, +.hljs-selector-attr, +.hljs-selector-pseudo, +.hljs-addition, +.hljs-variable, +.hljs-template-tag, +.hljs-template-variable { + color: #a6e22e; +} + +.hljs-comment, +.hljs-quote, +.hljs-deletion, +.hljs-meta { + color: #75715e; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-literal, +.hljs-doctag, +.hljs-title, +.hljs-section, +.hljs-type, +.hljs-selector-id { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/obsidian.css b/packages/ui/certd-client/src/components/highlight-styles/obsidian.css new file mode 100644 index 00000000..356630fa --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/obsidian.css @@ -0,0 +1,88 @@ +/** + * Obsidian style + * ported by Alexander Marenin (http://github.com/ioncreature) + */ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #282b2e; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-literal, +.hljs-selector-id { + color: #93c763; +} + +.hljs-number { + color: #ffcd22; +} + +.hljs { + color: #e0e2e4; +} + +.hljs-attribute { + color: #668bb0; +} + +.hljs-code, +.hljs-class .hljs-title, +.hljs-section { + color: white; +} + +.hljs-regexp, +.hljs-link { + color: #d39745; +} + +.hljs-meta { + color: #557182; +} + +.hljs-tag, +.hljs-name, +.hljs-bullet, +.hljs-subst, +.hljs-emphasis, +.hljs-type, +.hljs-built_in, +.hljs-selector-attr, +.hljs-selector-pseudo, +.hljs-addition, +.hljs-variable, +.hljs-template-tag, +.hljs-template-variable { + color: #8cbbad; +} + +.hljs-string, +.hljs-symbol { + color: #ec7600; +} + +.hljs-comment, +.hljs-quote, +.hljs-deletion { + color: #818e96; +} + +.hljs-selector-class { + color: #A082BD +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-literal, +.hljs-doctag, +.hljs-title, +.hljs-section, +.hljs-type, +.hljs-name, +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/ocean.css b/packages/ui/certd-client/src/components/highlight-styles/ocean.css new file mode 100644 index 00000000..5901581b --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/ocean.css @@ -0,0 +1,74 @@ +/* Ocean Dark Theme */ +/* https://github.com/gavsiu */ +/* Original theme - https://github.com/chriskempson/base16 */ + +/* Ocean Comment */ +.hljs-comment, +.hljs-quote { + color: #65737e; +} + +/* Ocean Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-tag, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class, +.hljs-regexp, +.hljs-deletion { + color: #bf616a; +} + +/* Ocean Orange */ +.hljs-number, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params, +.hljs-meta, +.hljs-link { + color: #d08770; +} + +/* Ocean Yellow */ +.hljs-attribute { + color: #ebcb8b; +} + +/* Ocean Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet, +.hljs-addition { + color: #a3be8c; +} + +/* Ocean Blue */ +.hljs-title, +.hljs-section { + color: #8fa1b3; +} + +/* Ocean Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #b48ead; +} + +.hljs { + display: block; + overflow-x: auto; + background: #2b303b; + color: #c0c5ce; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/paraiso-dark.css b/packages/ui/certd-client/src/components/highlight-styles/paraiso-dark.css new file mode 100644 index 00000000..e7292401 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/paraiso-dark.css @@ -0,0 +1,72 @@ +/* + Paraíso (dark) + Created by Jan T. Sott (http://github.com/idleberg) + Inspired by the art of Rubens LP (http://www.rubenslp.com.br) +*/ + +/* Paraíso Comment */ +.hljs-comment, +.hljs-quote { + color: #8d8687; +} + +/* Paraíso Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-tag, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class, +.hljs-regexp, +.hljs-link, +.hljs-meta { + color: #ef6155; +} + +/* Paraíso Orange */ +.hljs-number, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params, +.hljs-deletion { + color: #f99b15; +} + +/* Paraíso Yellow */ +.hljs-title, +.hljs-section, +.hljs-attribute { + color: #fec418; +} + +/* Paraíso Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet, +.hljs-addition { + color: #48b685; +} + +/* Paraíso Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #815ba4; +} + +.hljs { + display: block; + overflow-x: auto; + background: #2f1e2e; + color: #a39e9b; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/paraiso-light.css b/packages/ui/certd-client/src/components/highlight-styles/paraiso-light.css new file mode 100644 index 00000000..944857cd --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/paraiso-light.css @@ -0,0 +1,72 @@ +/* + Paraíso (light) + Created by Jan T. Sott (http://github.com/idleberg) + Inspired by the art of Rubens LP (http://www.rubenslp.com.br) +*/ + +/* Paraíso Comment */ +.hljs-comment, +.hljs-quote { + color: #776e71; +} + +/* Paraíso Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-tag, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class, +.hljs-regexp, +.hljs-link, +.hljs-meta { + color: #ef6155; +} + +/* Paraíso Orange */ +.hljs-number, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params, +.hljs-deletion { + color: #f99b15; +} + +/* Paraíso Yellow */ +.hljs-title, +.hljs-section, +.hljs-attribute { + color: #fec418; +} + +/* Paraíso Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet, +.hljs-addition { + color: #48b685; +} + +/* Paraíso Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #815ba4; +} + +.hljs { + display: block; + overflow-x: auto; + background: #e7e9db; + color: #4f424c; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/pojoaque.css b/packages/ui/certd-client/src/components/highlight-styles/pojoaque.css new file mode 100644 index 00000000..2e07847b --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/pojoaque.css @@ -0,0 +1,83 @@ +/* + +Pojoaque Style by Jason Tate +http://web-cms-designs.com/ftopict-10-pojoaque-style-for-highlight-js-code-highlighter.html +Based on Solarized Style from http://ethanschoonover.com/solarized + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + color: #dccf8f; + background: url(./pojoaque.jpg) repeat scroll left top #181914; +} + +.hljs-comment, +.hljs-quote { + color: #586e75; + font-style: italic; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-literal, +.hljs-addition { + color: #b64926; +} + +.hljs-number, +.hljs-string, +.hljs-doctag, +.hljs-regexp { + color: #468966; +} + +.hljs-title, +.hljs-section, +.hljs-built_in, +.hljs-name { + color: #ffb03b; +} + +.hljs-variable, +.hljs-template-variable, +.hljs-class .hljs-title, +.hljs-type, +.hljs-tag { + color: #b58900; +} + +.hljs-attribute { + color: #b89859; +} + +.hljs-symbol, +.hljs-bullet, +.hljs-link, +.hljs-subst, +.hljs-meta { + color: #cb4b16; +} + +.hljs-deletion { + color: #dc322f; +} + +.hljs-selector-id, +.hljs-selector-class { + color: #d3a60c; +} + +.hljs-formula { + background: #073642; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/pojoaque.jpg b/packages/ui/certd-client/src/components/highlight-styles/pojoaque.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9c07d4ab40b6d77e90ff69f0012bcd33b21d31c3 GIT binary patch literal 1186 zcmZXSe^8Tk9LK-kXFs3)f@f?)Cddzw3v4wdZyXQ;4x3=;Ja*N#%n9ik!UGmt9H3k0 zJST|5jOc(ID$FQt3C?jQZBws#kXolO1lg9Pba9BB=Q+UEBX!nY@6Uhl&+ofe$Q$y5 z@ci`~)&qzDP(lOiQ5p?p z(`j^e7!yUAVHk%K#^GQXn?s0=VLYCI$HRoe=xCuZ>A6A3@sxEP#XqNFpIb=0)KQ#Nss_tD17;m4@$JKL;LR|K|QF3f%!L5+s(9Ft8SQ zG|~pGpEGFW5Z|OA)-O@mNHy-g@7m8JTf?kl@vUKBGmw)Y*9sDRNr3PN!IKefWaydTe1D zjzpyzPnD3}hBNaS4aFX7=0&~I*Hu7#4au@qVBglH#-m;QFOx_`=j z{EqRY#Eh*yoWP^pa4H>8GH{rO?!_+xwL0(k4yL^D%^nBkJ*UI;Lx;ped8d|f*S_s@ z3~ilcRC(&NT#9Gn#UD;o^EYSMXDMf%XcUi3>;WXXD-QX3P9wMyP7eA&RS{)h5{??W3^Rq=goFJ>?lA~J- zdYe>!xvYLW*fPT0RK7wsJRg^?x#W1*GP9_f`6t>QD_X>0d!owyN>nO2?U5}|3?hX_UZYT@^>S!9eB~bZ9U`q;`U)@L670o1g z`Hd}h<_WRvUc|n*%v4Hbb-4tJD40iyF^q%g*&!6>hkYDvi-{Uc4yTM zzcthN4Z{ka!+F_KzYV#yWi;c^X^q6g`pD8cp?$Kl?hCz0s^a|mH%P!CF%*<6k^~i` zT5Mi-t5-frUcHkk^Qh}+N)Kz1&Bi95`oNc|quI>tUi~BY>xcF9(%tv2i{G6kE9*q~ qCoAGl20`)w0rdgp9H%Q=M5|p`hOhFz6$I%Y&ncY8>c?7PXyh+SL&XXJ literal 0 HcmV?d00001 diff --git a/packages/ui/certd-client/src/components/highlight-styles/purebasic.css b/packages/ui/certd-client/src/components/highlight-styles/purebasic.css new file mode 100644 index 00000000..5ce9b9e0 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/purebasic.css @@ -0,0 +1,96 @@ +/* + +PureBASIC native IDE style ( version 1.0 - April 2016 ) + +by Tristano Ajmone + +Public Domain + +NOTE_1: PureBASIC code syntax highlighting only applies the following classes: + .hljs-comment + .hljs-function + .hljs-keywords + .hljs-string + .hljs-symbol + + Other classes are added here for the benefit of styling other languages with the look and feel of PureBASIC native IDE style. + If you need to customize a stylesheet for PureBASIC only, remove all non-relevant classes -- PureBASIC-related classes are followed by + a "--- used for PureBASIC ... ---" comment on same line. + +NOTE_2: Color names provided in comments were derived using "Name that Color" online tool: + http://chir.ag/projects/name-that-color +*/ + +.hljs { /* Common set of rules required by highlight.js (don'r remove!) */ + display: block; + overflow-x: auto; + padding: 0.5em; + background: #FFFFDF; /* Half and Half (approx.) */ +/* --- Uncomment to add PureBASIC native IDE styled font! + font-family: Consolas; +*/ +} + +.hljs, /* --- used for PureBASIC base color --- */ +.hljs-type, /* --- used for PureBASIC Procedures return type --- */ +.hljs-function, /* --- used for wrapping PureBASIC Procedures definitions --- */ +.hljs-name, +.hljs-number, +.hljs-attr, +.hljs-params, +.hljs-subst { + color: #000000; /* Black */ +} + +.hljs-comment, /* --- used for PureBASIC Comments --- */ +.hljs-regexp, +.hljs-section, +.hljs-selector-pseudo, +.hljs-addition { + color: #00AAAA; /* Persian Green (approx.) */ +} + +.hljs-title, /* --- used for PureBASIC Procedures Names --- */ +.hljs-tag, +.hljs-variable, +.hljs-code { + color: #006666; /* Blue Stone (approx.) */ +} + +.hljs-keyword, /* --- used for PureBASIC Keywords --- */ +.hljs-class, +.hljs-meta-keyword, +.hljs-selector-class, +.hljs-built_in, +.hljs-builtin-name { + color: #006666; /* Blue Stone (approx.) */ + font-weight: bold; +} + +.hljs-string, /* --- used for PureBASIC Strings --- */ +.hljs-selector-attr { + color: #0080FF; /* Azure Radiance (approx.) */ +} + +.hljs-symbol, /* --- used for PureBASIC Constants --- */ +.hljs-link, +.hljs-deletion, +.hljs-attribute { + color: #924B72; /* Cannon Pink (approx.) */ +} + +.hljs-meta, +.hljs-literal, +.hljs-selector-id { + color: #924B72; /* Cannon Pink (approx.) */ + font-weight: bold; +} + +.hljs-strong, +.hljs-name { + font-weight: bold; +} + +.hljs-emphasis { + font-style: italic; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/qtcreator_dark.css b/packages/ui/certd-client/src/components/highlight-styles/qtcreator_dark.css new file mode 100644 index 00000000..7aa56a36 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/qtcreator_dark.css @@ -0,0 +1,83 @@ +/* + +Qt Creator dark color scheme + +*/ + + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #000000; +} + +.hljs, +.hljs-subst, +.hljs-tag, +.hljs-title { + color: #aaaaaa; +} + +.hljs-strong, +.hljs-emphasis { + color: #a8a8a2; +} + +.hljs-bullet, +.hljs-quote, +.hljs-number, +.hljs-regexp, +.hljs-literal { + color: #ff55ff; +} + +.hljs-code +.hljs-selector-class { + color: #aaaaff; +} + +.hljs-emphasis, +.hljs-stronge, +.hljs-type { + font-style: italic; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-function, +.hljs-section, +.hljs-symbol, +.hljs-name { + color: #ffff55; +} + +.hljs-attribute { + color: #ff5555; +} + +.hljs-variable, +.hljs-params, +.hljs-class .hljs-title { + color: #8888ff; +} + +.hljs-string, +.hljs-selector-id, +.hljs-selector-attr, +.hljs-selector-pseudo, +.hljs-type, +.hljs-built_in, +.hljs-builtin-name, +.hljs-template-tag, +.hljs-template-variable, +.hljs-addition, +.hljs-link { + color: #ff55ff; +} + +.hljs-comment, +.hljs-meta, +.hljs-deletion { + color: #55ffff; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/qtcreator_light.css b/packages/ui/certd-client/src/components/highlight-styles/qtcreator_light.css new file mode 100644 index 00000000..1efa2c66 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/qtcreator_light.css @@ -0,0 +1,83 @@ +/* + +Qt Creator light color scheme + +*/ + + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #ffffff; +} + +.hljs, +.hljs-subst, +.hljs-tag, +.hljs-title { + color: #000000; +} + +.hljs-strong, +.hljs-emphasis { + color: #000000; +} + +.hljs-bullet, +.hljs-quote, +.hljs-number, +.hljs-regexp, +.hljs-literal { + color: #000080; +} + +.hljs-code +.hljs-selector-class { + color: #800080; +} + +.hljs-emphasis, +.hljs-stronge, +.hljs-type { + font-style: italic; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-function, +.hljs-section, +.hljs-symbol, +.hljs-name { + color: #808000; +} + +.hljs-attribute { + color: #800000; +} + +.hljs-variable, +.hljs-params, +.hljs-class .hljs-title { + color: #0055AF; +} + +.hljs-string, +.hljs-selector-id, +.hljs-selector-attr, +.hljs-selector-pseudo, +.hljs-type, +.hljs-built_in, +.hljs-builtin-name, +.hljs-template-tag, +.hljs-template-variable, +.hljs-addition, +.hljs-link { + color: #008000; +} + +.hljs-comment, +.hljs-meta, +.hljs-deletion { + color: #008000; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/railscasts.css b/packages/ui/certd-client/src/components/highlight-styles/railscasts.css new file mode 100644 index 00000000..008cdc5b --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/railscasts.css @@ -0,0 +1,106 @@ +/* + +Railscasts-like style (c) Visoft, Inc. (Damien White) + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #232323; + color: #e6e1dc; +} + +.hljs-comment, +.hljs-quote { + color: #bc9458; + font-style: italic; +} + +.hljs-keyword, +.hljs-selector-tag { + color: #c26230; +} + +.hljs-string, +.hljs-number, +.hljs-regexp, +.hljs-variable, +.hljs-template-variable { + color: #a5c261; +} + +.hljs-subst { + color: #519f50; +} + +.hljs-tag, +.hljs-name { + color: #e8bf6a; +} + +.hljs-type { + color: #da4939; +} + + +.hljs-symbol, +.hljs-bullet, +.hljs-built_in, +.hljs-builtin-name, +.hljs-attr, +.hljs-link { + color: #6d9cbe; +} + +.hljs-params { + color: #d0d0ff; +} + +.hljs-attribute { + color: #cda869; +} + +.hljs-meta { + color: #9b859d; +} + +.hljs-title, +.hljs-section { + color: #ffc66d; +} + +.hljs-addition { + background-color: #144212; + color: #e6e1dc; + display: inline-block; + width: 100%; +} + +.hljs-deletion { + background-color: #600; + color: #e6e1dc; + display: inline-block; + width: 100%; +} + +.hljs-selector-class { + color: #9b703f; +} + +.hljs-selector-id { + color: #8b98ab; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} + +.hljs-link { + text-decoration: underline; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/rainbow.css b/packages/ui/certd-client/src/components/highlight-styles/rainbow.css new file mode 100644 index 00000000..905eb8ef --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/rainbow.css @@ -0,0 +1,85 @@ +/* + +Style with support for rainbow parens + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #474949; + color: #d1d9e1; +} + + +.hljs-comment, +.hljs-quote { + color: #969896; + font-style: italic; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-literal, +.hljs-type, +.hljs-addition { + color: #cc99cc; +} + +.hljs-number, +.hljs-selector-attr, +.hljs-selector-pseudo { + color: #f99157; +} + +.hljs-string, +.hljs-doctag, +.hljs-regexp { + color: #8abeb7; +} + +.hljs-title, +.hljs-name, +.hljs-section, +.hljs-built_in { + color: #b5bd68; +} + +.hljs-variable, +.hljs-template-variable, +.hljs-selector-id, +.hljs-class .hljs-title { + color: #ffcc66; +} + +.hljs-section, +.hljs-name, +.hljs-strong { + font-weight: bold; +} + +.hljs-symbol, +.hljs-bullet, +.hljs-subst, +.hljs-meta, +.hljs-link { + color: #f99157; +} + +.hljs-deletion { + color: #dc322f; +} + +.hljs-formula { + background: #eee8d5; +} + +.hljs-attr, +.hljs-attribute { + color: #81a2be; +} + +.hljs-emphasis { + font-style: italic; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/routeros.css b/packages/ui/certd-client/src/components/highlight-styles/routeros.css new file mode 100644 index 00000000..ebe23990 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/routeros.css @@ -0,0 +1,108 @@ +/* + + highlight.js style for Microtik RouterOS script + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #F0F0F0; +} + +/* Base color: saturation 0; */ + +.hljs, +.hljs-subst { + color: #444; +} + +.hljs-comment { + color: #888888; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-meta-keyword, +.hljs-doctag, +.hljs-name { + font-weight: bold; +} + +.hljs-attribute { + color: #0E9A00; +} + +.hljs-function { + color: #99069A; +} + +.hljs-builtin-name { + color: #99069A; +} + +/* User color: hue: 0 */ + +.hljs-type, +.hljs-string, +.hljs-number, +.hljs-selector-id, +.hljs-selector-class, +.hljs-quote, +.hljs-template-tag, +.hljs-deletion { + color: #880000; +} + +.hljs-title, +.hljs-section { + color: #880000; + font-weight: bold; +} + +.hljs-regexp, +.hljs-symbol, +.hljs-variable, +.hljs-template-variable, +.hljs-link, +.hljs-selector-attr, +.hljs-selector-pseudo { + color: #BC6060; +} + + +/* Language color: hue: 90; */ + +.hljs-literal { + color: #78A960; +} + +.hljs-built_in, +.hljs-bullet, +.hljs-code, +.hljs-addition { + color: #0C9A9A; +} + + +/* Meta color: hue: 200 */ + +.hljs-meta { + color: #1f7199; +} + +.hljs-meta-string { + color: #4d99bf; +} + + +/* Misc effects */ + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/school-book.css b/packages/ui/certd-client/src/components/highlight-styles/school-book.css new file mode 100644 index 00000000..964b51d8 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/school-book.css @@ -0,0 +1,72 @@ +/* + +School Book style from goldblog.com.ua (c) Zaripov Yura + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 15px 0.5em 0.5em 30px; + font-size: 11px; + line-height:16px; +} + +pre{ + background:#f6f6ae url(./school-book.png); + border-top: solid 2px #d2e8b9; + border-bottom: solid 1px #d2e8b9; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-literal { + color:#005599; + font-weight:bold; +} + +.hljs, +.hljs-subst { + color: #3e5915; +} + +.hljs-string, +.hljs-title, +.hljs-section, +.hljs-type, +.hljs-symbol, +.hljs-bullet, +.hljs-attribute, +.hljs-built_in, +.hljs-builtin-name, +.hljs-addition, +.hljs-variable, +.hljs-template-tag, +.hljs-template-variable, +.hljs-link { + color: #2c009f; +} + +.hljs-comment, +.hljs-quote, +.hljs-deletion, +.hljs-meta { + color: #e60415; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-literal, +.hljs-doctag, +.hljs-title, +.hljs-section, +.hljs-type, +.hljs-name, +.hljs-selector-id, +.hljs-strong { + font-weight: bold; +} + +.hljs-emphasis { + font-style: italic; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/school-book.png b/packages/ui/certd-client/src/components/highlight-styles/school-book.png new file mode 100644 index 0000000000000000000000000000000000000000..956e9790a0e2c079b3d568348ff3accd1d9cac30 GIT binary patch literal 486 zcmeAS@N?(olHy`uVBq!ia0y~yV7?7x3vjRjNjAS6Ga$v1?&#~tz_9*=IcwKTAYZb? zHKHUqKdq!Zu_%?nF(p4KRlzeiF+DXXH8G{K@MNkD0|R4)r;B4q#jQ7Ycl#YS5MfK$ z?b^fh#qmaEhFDxvyThwfhdfkOPApt1lr{NA;Vr%uzxJuVIyzm(ed_8_-0$LLU})H&o5Re&aDemE>EG#(|F^t9_pa-H z_Mf?rMVrs}-M?S|?ZdY@c6s41zy8~}@a{v&#Ea7V)wJ$+#K|u$5UvWCdFLwGac}6w{_s*=8A6L7Rfc|9gboFyt I=akR{0OLZ+qyPW_ literal 0 HcmV?d00001 diff --git a/packages/ui/certd-client/src/components/highlight-styles/solarized-dark.css b/packages/ui/certd-client/src/components/highlight-styles/solarized-dark.css new file mode 100644 index 00000000..b4c0da1f --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/solarized-dark.css @@ -0,0 +1,84 @@ +/* + +Orginal Style from ethanschoonover.com/solarized (c) Jeremy Hull + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #002b36; + color: #839496; +} + +.hljs-comment, +.hljs-quote { + color: #586e75; +} + +/* Solarized Green */ +.hljs-keyword, +.hljs-selector-tag, +.hljs-addition { + color: #859900; +} + +/* Solarized Cyan */ +.hljs-number, +.hljs-string, +.hljs-meta .hljs-meta-string, +.hljs-literal, +.hljs-doctag, +.hljs-regexp { + color: #2aa198; +} + +/* Solarized Blue */ +.hljs-title, +.hljs-section, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #268bd2; +} + +/* Solarized Yellow */ +.hljs-attribute, +.hljs-attr, +.hljs-variable, +.hljs-template-variable, +.hljs-class .hljs-title, +.hljs-type { + color: #b58900; +} + +/* Solarized Orange */ +.hljs-symbol, +.hljs-bullet, +.hljs-subst, +.hljs-meta, +.hljs-meta .hljs-keyword, +.hljs-selector-attr, +.hljs-selector-pseudo, +.hljs-link { + color: #cb4b16; +} + +/* Solarized Red */ +.hljs-built_in, +.hljs-deletion { + color: #dc322f; +} + +.hljs-formula { + background: #073642; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/solarized-light.css b/packages/ui/certd-client/src/components/highlight-styles/solarized-light.css new file mode 100644 index 00000000..fdcfcc72 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/solarized-light.css @@ -0,0 +1,84 @@ +/* + +Orginal Style from ethanschoonover.com/solarized (c) Jeremy Hull + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #fdf6e3; + color: #657b83; +} + +.hljs-comment, +.hljs-quote { + color: #93a1a1; +} + +/* Solarized Green */ +.hljs-keyword, +.hljs-selector-tag, +.hljs-addition { + color: #859900; +} + +/* Solarized Cyan */ +.hljs-number, +.hljs-string, +.hljs-meta .hljs-meta-string, +.hljs-literal, +.hljs-doctag, +.hljs-regexp { + color: #2aa198; +} + +/* Solarized Blue */ +.hljs-title, +.hljs-section, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class { + color: #268bd2; +} + +/* Solarized Yellow */ +.hljs-attribute, +.hljs-attr, +.hljs-variable, +.hljs-template-variable, +.hljs-class .hljs-title, +.hljs-type { + color: #b58900; +} + +/* Solarized Orange */ +.hljs-symbol, +.hljs-bullet, +.hljs-subst, +.hljs-meta, +.hljs-meta .hljs-keyword, +.hljs-selector-attr, +.hljs-selector-pseudo, +.hljs-link { + color: #cb4b16; +} + +/* Solarized Red */ +.hljs-built_in, +.hljs-deletion { + color: #dc322f; +} + +.hljs-formula { + background: #eee8d5; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/sunburst.css b/packages/ui/certd-client/src/components/highlight-styles/sunburst.css new file mode 100644 index 00000000..f56dd5e9 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/sunburst.css @@ -0,0 +1,102 @@ +/* + +Sunburst-like style (c) Vasily Polovnyov + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #000; + color: #f8f8f8; +} + +.hljs-comment, +.hljs-quote { + color: #aeaeae; + font-style: italic; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-type { + color: #e28964; +} + +.hljs-string { + color: #65b042; +} + +.hljs-subst { + color: #daefa3; +} + +.hljs-regexp, +.hljs-link { + color: #e9c062; +} + +.hljs-title, +.hljs-section, +.hljs-tag, +.hljs-name { + color: #89bdff; +} + +.hljs-class .hljs-title, +.hljs-doctag { + text-decoration: underline; +} + +.hljs-symbol, +.hljs-bullet, +.hljs-number { + color: #3387cc; +} + +.hljs-params, +.hljs-variable, +.hljs-template-variable { + color: #3e87e3; +} + +.hljs-attribute { + color: #cda869; +} + +.hljs-meta { + color: #8996a8; +} + +.hljs-formula { + background-color: #0e2231; + color: #f8f8f8; + font-style: italic; +} + +.hljs-addition { + background-color: #253b22; + color: #f8f8f8; +} + +.hljs-deletion { + background-color: #420e09; + color: #f8f8f8; +} + +.hljs-selector-class { + color: #9b703f; +} + +.hljs-selector-id { + color: #8b98ab; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/tomorrow-night-blue.css b/packages/ui/certd-client/src/components/highlight-styles/tomorrow-night-blue.css new file mode 100644 index 00000000..78e59cc8 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/tomorrow-night-blue.css @@ -0,0 +1,75 @@ +/* Tomorrow Night Blue Theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ + +/* Tomorrow Comment */ +.hljs-comment, +.hljs-quote { + color: #7285b7; +} + +/* Tomorrow Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-tag, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class, +.hljs-regexp, +.hljs-deletion { + color: #ff9da4; +} + +/* Tomorrow Orange */ +.hljs-number, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params, +.hljs-meta, +.hljs-link { + color: #ffc58f; +} + +/* Tomorrow Yellow */ +.hljs-attribute { + color: #ffeead; +} + +/* Tomorrow Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet, +.hljs-addition { + color: #d1f1a9; +} + +/* Tomorrow Blue */ +.hljs-title, +.hljs-section { + color: #bbdaff; +} + +/* Tomorrow Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #ebbbff; +} + +.hljs { + display: block; + overflow-x: auto; + background: #002451; + color: white; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/tomorrow-night-bright.css b/packages/ui/certd-client/src/components/highlight-styles/tomorrow-night-bright.css new file mode 100644 index 00000000..e05af8ae --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/tomorrow-night-bright.css @@ -0,0 +1,74 @@ +/* Tomorrow Night Bright Theme */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ + +/* Tomorrow Comment */ +.hljs-comment, +.hljs-quote { + color: #969896; +} + +/* Tomorrow Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-tag, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class, +.hljs-regexp, +.hljs-deletion { + color: #d54e53; +} + +/* Tomorrow Orange */ +.hljs-number, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params, +.hljs-meta, +.hljs-link { + color: #e78c45; +} + +/* Tomorrow Yellow */ +.hljs-attribute { + color: #e7c547; +} + +/* Tomorrow Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet, +.hljs-addition { + color: #b9ca4a; +} + +/* Tomorrow Blue */ +.hljs-title, +.hljs-section { + color: #7aa6da; +} + +/* Tomorrow Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #c397d8; +} + +.hljs { + display: block; + overflow-x: auto; + background: black; + color: #eaeaea; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/tomorrow-night-eighties.css b/packages/ui/certd-client/src/components/highlight-styles/tomorrow-night-eighties.css new file mode 100644 index 00000000..08fd51c7 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/tomorrow-night-eighties.css @@ -0,0 +1,74 @@ +/* Tomorrow Night Eighties Theme */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ + +/* Tomorrow Comment */ +.hljs-comment, +.hljs-quote { + color: #999999; +} + +/* Tomorrow Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-tag, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class, +.hljs-regexp, +.hljs-deletion { + color: #f2777a; +} + +/* Tomorrow Orange */ +.hljs-number, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params, +.hljs-meta, +.hljs-link { + color: #f99157; +} + +/* Tomorrow Yellow */ +.hljs-attribute { + color: #ffcc66; +} + +/* Tomorrow Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet, +.hljs-addition { + color: #99cc99; +} + +/* Tomorrow Blue */ +.hljs-title, +.hljs-section { + color: #6699cc; +} + +/* Tomorrow Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #cc99cc; +} + +.hljs { + display: block; + overflow-x: auto; + background: #2d2d2d; + color: #cccccc; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/tomorrow-night.css b/packages/ui/certd-client/src/components/highlight-styles/tomorrow-night.css new file mode 100644 index 00000000..ddd270a4 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/tomorrow-night.css @@ -0,0 +1,75 @@ +/* Tomorrow Night Theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ +/* Original theme - https://github.com/chriskempson/tomorrow-theme */ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ + +/* Tomorrow Comment */ +.hljs-comment, +.hljs-quote { + color: #969896; +} + +/* Tomorrow Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-tag, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class, +.hljs-regexp, +.hljs-deletion { + color: #cc6666; +} + +/* Tomorrow Orange */ +.hljs-number, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params, +.hljs-meta, +.hljs-link { + color: #de935f; +} + +/* Tomorrow Yellow */ +.hljs-attribute { + color: #f0c674; +} + +/* Tomorrow Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet, +.hljs-addition { + color: #b5bd68; +} + +/* Tomorrow Blue */ +.hljs-title, +.hljs-section { + color: #81a2be; +} + +/* Tomorrow Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #b294bb; +} + +.hljs { + display: block; + overflow-x: auto; + background: #1d1f21; + color: #c5c8c6; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/tomorrow.css b/packages/ui/certd-client/src/components/highlight-styles/tomorrow.css new file mode 100644 index 00000000..026a62fe --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/tomorrow.css @@ -0,0 +1,72 @@ +/* http://jmblog.github.com/color-themes-for-google-code-highlightjs */ + +/* Tomorrow Comment */ +.hljs-comment, +.hljs-quote { + color: #8e908c; +} + +/* Tomorrow Red */ +.hljs-variable, +.hljs-template-variable, +.hljs-tag, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class, +.hljs-regexp, +.hljs-deletion { + color: #c82829; +} + +/* Tomorrow Orange */ +.hljs-number, +.hljs-built_in, +.hljs-builtin-name, +.hljs-literal, +.hljs-type, +.hljs-params, +.hljs-meta, +.hljs-link { + color: #f5871f; +} + +/* Tomorrow Yellow */ +.hljs-attribute { + color: #eab700; +} + +/* Tomorrow Green */ +.hljs-string, +.hljs-symbol, +.hljs-bullet, +.hljs-addition { + color: #718c00; +} + +/* Tomorrow Blue */ +.hljs-title, +.hljs-section { + color: #4271ae; +} + +/* Tomorrow Purple */ +.hljs-keyword, +.hljs-selector-tag { + color: #8959a8; +} + +.hljs { + display: block; + overflow-x: auto; + background: white; + color: #4d4d4c; + padding: 0.5em; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/vs.css b/packages/ui/certd-client/src/components/highlight-styles/vs.css new file mode 100644 index 00000000..c5d07d31 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/vs.css @@ -0,0 +1,68 @@ +/* + +Visual Studio-like style based on original C# coloring by Jason Diamond + +*/ +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: white; + color: black; +} + +.hljs-comment, +.hljs-quote, +.hljs-variable { + color: #008000; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-built_in, +.hljs-name, +.hljs-tag { + color: #00f; +} + +.hljs-string, +.hljs-title, +.hljs-section, +.hljs-attribute, +.hljs-literal, +.hljs-template-tag, +.hljs-template-variable, +.hljs-type, +.hljs-addition { + color: #a31515; +} + +.hljs-deletion, +.hljs-selector-attr, +.hljs-selector-pseudo, +.hljs-meta { + color: #2b91af; +} + +.hljs-doctag { + color: #808080; +} + +.hljs-attr { + color: #f00; +} + +.hljs-symbol, +.hljs-bullet, +.hljs-link { + color: #00b0e8; +} + + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/vs2015.css b/packages/ui/certd-client/src/components/highlight-styles/vs2015.css new file mode 100644 index 00000000..d1d9be3c --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/vs2015.css @@ -0,0 +1,115 @@ +/* + * Visual Studio 2015 dark style + * Author: Nicolas LLOBERA + */ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #1E1E1E; + color: #DCDCDC; +} + +.hljs-keyword, +.hljs-literal, +.hljs-symbol, +.hljs-name { + color: #569CD6; +} +.hljs-link { + color: #569CD6; + text-decoration: underline; +} + +.hljs-built_in, +.hljs-type { + color: #4EC9B0; +} + +.hljs-number, +.hljs-class { + color: #B8D7A3; +} + +.hljs-string, +.hljs-meta-string { + color: #D69D85; +} + +.hljs-regexp, +.hljs-template-tag { + color: #9A5334; +} + +.hljs-subst, +.hljs-function, +.hljs-title, +.hljs-params, +.hljs-formula { + color: #DCDCDC; +} + +.hljs-comment, +.hljs-quote { + color: #57A64A; + font-style: italic; +} + +.hljs-doctag { + color: #608B4E; +} + +.hljs-meta, +.hljs-meta-keyword, +.hljs-tag { + color: #9B9B9B; +} + +.hljs-variable, +.hljs-template-variable { + color: #BD63C5; +} + +.hljs-attr, +.hljs-attribute, +.hljs-builtin-name { + color: #9CDCFE; +} + +.hljs-section { + color: gold; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} + +/*.hljs-code { + font-family:'Monospace'; +}*/ + +.hljs-bullet, +.hljs-selector-tag, +.hljs-selector-id, +.hljs-selector-class, +.hljs-selector-attr, +.hljs-selector-pseudo { + color: #D7BA7D; +} + +.hljs-addition { + background-color: #144212; + display: inline-block; + width: 100%; +} + +.hljs-deletion { + background-color: #600; + display: inline-block; + width: 100%; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/xcode.css b/packages/ui/certd-client/src/components/highlight-styles/xcode.css new file mode 100644 index 00000000..43dddad8 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/xcode.css @@ -0,0 +1,93 @@ +/* + +XCode style (c) Angel Garcia + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #fff; + color: black; +} + +.hljs-comment, +.hljs-quote { + color: #006a00; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-literal { + color: #aa0d91; +} + +.hljs-name { + color: #008; +} + +.hljs-variable, +.hljs-template-variable { + color: #660; +} + +.hljs-string { + color: #c41a16; +} + +.hljs-regexp, +.hljs-link { + color: #080; +} + +.hljs-title, +.hljs-tag, +.hljs-symbol, +.hljs-bullet, +.hljs-number, +.hljs-meta { + color: #1c00cf; +} + +.hljs-section, +.hljs-class .hljs-title, +.hljs-type, +.hljs-attr, +.hljs-built_in, +.hljs-builtin-name, +.hljs-params { + color: #5c2699; +} + +.hljs-attribute, +.hljs-subst { + color: #000; +} + +.hljs-formula { + background-color: #eee; + font-style: italic; +} + +.hljs-addition { + background-color: #baeeba; +} + +.hljs-deletion { + background-color: #ffc8bd; +} + +.hljs-selector-id, +.hljs-selector-class { + color: #9b703f; +} + +.hljs-doctag, +.hljs-strong { + font-weight: bold; +} + +.hljs-emphasis { + font-style: italic; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/xt256.css b/packages/ui/certd-client/src/components/highlight-styles/xt256.css new file mode 100644 index 00000000..58df82cb --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/xt256.css @@ -0,0 +1,92 @@ + +/* + xt256.css + + Contact: initbar [at] protonmail [dot] ch + : github.com/initbar +*/ + +.hljs { + display: block; + overflow-x: auto; + color: #eaeaea; + background: #000; + padding: 0.5; +} + +.hljs-subst { + color: #eaeaea; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} + +.hljs-builtin-name, +.hljs-type { + color: #eaeaea; +} + +.hljs-params { + color: #da0000; +} + +.hljs-literal, +.hljs-number, +.hljs-name { + color: #ff0000; + font-weight: bolder; +} + +.hljs-comment { + color: #969896; +} + +.hljs-selector-id, +.hljs-quote { + color: #00ffff; +} + +.hljs-template-variable, +.hljs-variable, +.hljs-title { + color: #00ffff; + font-weight: bold; +} + +.hljs-selector-class, +.hljs-keyword, +.hljs-symbol { + color: #fff000; +} + +.hljs-string, +.hljs-bullet { + color: #00ff00; +} + +.hljs-tag, +.hljs-section { + color: #000fff; +} + +.hljs-selector-tag { + color: #000fff; + font-weight: bold; +} + +.hljs-attribute, +.hljs-built_in, +.hljs-regexp, +.hljs-link { + color: #ff00ff; +} + +.hljs-meta { + color: #fff; + font-weight: bolder; +} diff --git a/packages/ui/certd-client/src/components/highlight-styles/zenburn.css b/packages/ui/certd-client/src/components/highlight-styles/zenburn.css new file mode 100644 index 00000000..07be5020 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight-styles/zenburn.css @@ -0,0 +1,80 @@ +/* + +Zenburn style from voldmar.ru (c) Vladimir Epifanov +based on dark.css by Ivan Sagalaev + +*/ + +.hljs { + display: block; + overflow-x: auto; + padding: 0.5em; + background: #3f3f3f; + color: #dcdcdc; +} + +.hljs-keyword, +.hljs-selector-tag, +.hljs-tag { + color: #e3ceab; +} + +.hljs-template-tag { + color: #dcdcdc; +} + +.hljs-number { + color: #8cd0d3; +} + +.hljs-variable, +.hljs-template-variable, +.hljs-attribute { + color: #efdcbc; +} + +.hljs-literal { + color: #efefaf; +} + +.hljs-subst { + color: #8f8f8f; +} + +.hljs-title, +.hljs-name, +.hljs-selector-id, +.hljs-selector-class, +.hljs-section, +.hljs-type { + color: #efef8f; +} + +.hljs-symbol, +.hljs-bullet, +.hljs-link { + color: #dca3a3; +} + +.hljs-deletion, +.hljs-string, +.hljs-built_in, +.hljs-builtin-name { + color: #cc9393; +} + +.hljs-addition, +.hljs-comment, +.hljs-quote, +.hljs-meta { + color: #7f9f7f; +} + + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} diff --git a/packages/ui/certd-client/src/components/highlight/index.vue b/packages/ui/certd-client/src/components/highlight/index.vue new file mode 100644 index 00000000..67388235 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight/index.vue @@ -0,0 +1,66 @@ + + + + + diff --git a/packages/ui/certd-client/src/components/highlight/libs/htmlFormat.js b/packages/ui/certd-client/src/components/highlight/libs/htmlFormat.js new file mode 100644 index 00000000..637e1ab5 --- /dev/null +++ b/packages/ui/certd-client/src/components/highlight/libs/htmlFormat.js @@ -0,0 +1,365 @@ +/* eslint-disable */ + +// 功能 +// 将HTML字符串格式化 + +const format = (function() { + function style_html(html_source, indent_size, indent_character, max_char) { + var Parser, multi_parser; + function Parser() { + this.pos = 0; + this.token = ''; + this.current_mode = 'CONTENT'; + this.tags = { + parent: 'parent1', + parentcount: 1, + parent1: '' + }; + this.tag_type = ''; + this.token_text = this.last_token = this.last_text = this.token_type = ''; + this.Utils = { + whitespace: "\n\r\t ".split(''), + single_token: 'br,input,link,meta,!doctype,basefont,base,area,hr,wbr,param,img,isindex,?xml,embed'.split(','), + extra_liners: 'head,body,/html'.split(','), + in_array: function(what, arr) { + for (var i = 0; i < arr.length; i++) { + if (what === arr[i]) { + return true; + } + } + return false; + } + } + this.get_content = function() { + var char = ''; + var content = []; + var space = false; + while (this.input.charAt(this.pos) !== '<') { + if (this.pos >= this.input.length) { + return content.length ? content.join('') : ['', 'TK_EOF']; + } + char = this.input.charAt(this.pos); + this.pos++; + this.line_char_count++; + if (this.Utils.in_array(char, this.Utils.whitespace)) { + if (content.length) { + space = true; + } + this.line_char_count--; + continue; + } else if (space) { + if (this.line_char_count >= this.max_char) { + content.push('\n'); + for (var i = 0; i < this.indent_level; i++) { + content.push(this.indent_string); + } + this.line_char_count = 0; + } else { + content.push(' '); + this.line_char_count++; + } + space = false; + } + content.push(char); + } + return content.length ? content.join('') : ''; + } + this.get_script = function() { + var char = ''; + var content = []; + var reg_match = new RegExp('\<\/script' + '\>', 'igm'); + reg_match.lastIndex = this.pos; + var reg_array = reg_match.exec(this.input); + var end_script = reg_array ? reg_array.index: this.input.length; + while (this.pos < end_script) { + if (this.pos >= this.input.length) { + return content.length ? content.join('') : ['', 'TK_EOF']; + } + char = this.input.charAt(this.pos); + this.pos++; + content.push(char); + } + return content.length ? content.join('') : ''; + } + this.record_tag = function(tag) { + if (this.tags[tag + 'count']) { + this.tags[tag + 'count']++; + this.tags[tag + this.tags[tag + 'count']] = this.indent_level; + } else { + this.tags[tag + 'count'] = 1; + this.tags[tag + this.tags[tag + 'count']] = this.indent_level; + } + this.tags[tag + this.tags[tag + 'count'] + 'parent'] = this.tags.parent; + this.tags.parent = tag + this.tags[tag + 'count']; + } + this.retrieve_tag = function(tag) { + if (this.tags[tag + 'count']) { + var temp_parent = this.tags.parent; + while (temp_parent) { + if (tag + this.tags[tag + 'count'] === temp_parent) { + break; + } + temp_parent = this.tags[temp_parent + 'parent']; + } + if (temp_parent) { + this.indent_level = this.tags[tag + this.tags[tag + 'count']]; + this.tags.parent = this.tags[temp_parent + 'parent']; + } + delete this.tags[tag + this.tags[tag + 'count'] + 'parent']; + delete this.tags[tag + this.tags[tag + 'count']]; + if (this.tags[tag + 'count'] == 1) { + delete this.tags[tag + 'count']; + } else { + this.tags[tag + 'count']--; + } + } + } + this.get_tag = function() { + var char = ''; + var content = []; + var space = false; + do { + if (this.pos >= this.input.length) { + return content.length ? content.join('') : ['', 'TK_EOF']; + } + char = this.input.charAt(this.pos); + this.pos++; + this.line_char_count++; + if (this.Utils.in_array(char, this.Utils.whitespace)) { + space = true; + this.line_char_count--; + continue; + } + if (char === "'" || char === '"') { + if (!content[1] || content[1] !== '!') { + char += this.get_unformatted(char); + space = true; + } + } + if (char === '=') { + space = false; + } + if (content.length && content[content.length - 1] !== '=' && char !== '>' && space) { + if (this.line_char_count >= this.max_char) { + this.print_newline(false, content); + this.line_char_count = 0; + } else { + content.push(' '); + this.line_char_count++; + } + space = false; + } + content.push(char); + } while ( char !== '>'); + var tag_complete = content.join(''); + var tag_index; + if (tag_complete.indexOf(' ') != -1) { + tag_index = tag_complete.indexOf(' '); + } else { + tag_index = tag_complete.indexOf('>'); + } + var tag_check = tag_complete.substring(1, tag_index).toLowerCase(); + if (tag_complete.charAt(tag_complete.length - 2) === '/' || this.Utils.in_array(tag_check, this.Utils.single_token)) { + this.tag_type = 'SINGLE'; + } else if (tag_check === 'script') { + this.record_tag(tag_check); + this.tag_type = 'SCRIPT'; + } else if (tag_check === 'style') { + this.record_tag(tag_check); + this.tag_type = 'STYLE'; + } else if (tag_check.charAt(0) === '!') { + if (tag_check.indexOf('[if') != -1) { + if (tag_complete.indexOf('!IE') != -1) { + var comment = this.get_unformatted('-->', tag_complete); + content.push(comment); + } + this.tag_type = 'START'; + } else if (tag_check.indexOf('[endif') != -1) { + this.tag_type = 'END'; + this.unindent(); + } else if (tag_check.indexOf('[cdata[') != -1) { + var comment = this.get_unformatted(']]>', tag_complete); + content.push(comment); + this.tag_type = 'SINGLE'; + } else { + var comment = this.get_unformatted('-->', tag_complete); + content.push(comment); + this.tag_type = 'SINGLE'; + } + } else { + if (tag_check.charAt(0) === '/') { + this.retrieve_tag(tag_check.substring(1)); + this.tag_type = 'END'; + } else { + this.record_tag(tag_check); + this.tag_type = 'START'; + } + if (this.Utils.in_array(tag_check, this.Utils.extra_liners)) { + this.print_newline(true, this.output); + } + } + return content.join(''); + } + this.get_unformatted = function(delimiter, orig_tag) { + if (orig_tag && orig_tag.indexOf(delimiter) != -1) { + return ''; + } + var char = ''; + var content = ''; + var space = true; + do { + char = this.input.charAt(this.pos); + this.pos++ + if (this.Utils.in_array(char, this.Utils.whitespace)) { + if (!space) { + this.line_char_count--; + continue; + } + if (char === '\n' || char === '\r') { + content += '\n'; + for (var i = 0; i < this.indent_level; i++) { + content += this.indent_string; + } + space = false; + this.line_char_count = 0; + continue; + } + } + content += char; + this.line_char_count++; + space = true; + + } while ( content . indexOf ( delimiter ) == -1); + return content; + } + this.get_token = function() { + var token; + if (this.last_token === 'TK_TAG_SCRIPT') { + var temp_token = this.get_script(); + if (typeof temp_token !== 'string') { + return temp_token; + } + //token = js_beautify(temp_token, this.indent_size, this.indent_character, this.indent_level); + //return [token, 'TK_CONTENT']; + return [temp_token, 'TK_CONTENT']; + } + if (this.current_mode === 'CONTENT') { + token = this.get_content(); + if (typeof token !== 'string') { + return token; + } else { + return [token, 'TK_CONTENT']; + } + } + if (this.current_mode === 'TAG') { + token = this.get_tag(); + if (typeof token !== 'string') { + return token; + } else { + var tag_name_type = 'TK_TAG_' + this.tag_type; + return [token, tag_name_type]; + } + } + } + this.printer = function(js_source, indent_character, indent_size, max_char) { + this.input = js_source || ''; + this.output = []; + this.indent_character = indent_character || ' '; + this.indent_string = ''; + this.indent_size = indent_size || 2; + this.indent_level = 0; + this.max_char = max_char || 70; + this.line_char_count = 0; + for (var i = 0; i < this.indent_size; i++) { + this.indent_string += this.indent_character; + } + this.print_newline = function(ignore, arr) { + this.line_char_count = 0; + if (!arr || !arr.length) { + return; + } + if (!ignore) { + while (this.Utils.in_array(arr[arr.length - 1], this.Utils.whitespace)) { + arr.pop(); + } + } + arr.push('\n'); + for (var i = 0; i < this.indent_level; i++) { + arr.push(this.indent_string); + } + } + this.print_token = function(text) { + this.output.push(text); + } + this.indent = function() { + this.indent_level++; + } + this.unindent = function() { + if (this.indent_level > 0) { + this.indent_level--; + } + } + } + return this; + } + multi_parser = new Parser(); + multi_parser.printer(html_source, indent_character, indent_size); + while (true) { + var t = multi_parser.get_token(); + multi_parser.token_text = t[0]; + multi_parser.token_type = t[1]; + if (multi_parser.token_type === 'TK_EOF') { + break; + } + switch (multi_parser.token_type) { + case 'TK_TAG_START': + case 'TK_TAG_SCRIPT': + case 'TK_TAG_STYLE': + multi_parser.print_newline(false, multi_parser.output); + multi_parser.print_token(multi_parser.token_text); + multi_parser.indent(); + multi_parser.current_mode = 'CONTENT'; + break; + case 'TK_TAG_END': + multi_parser.print_newline(true, multi_parser.output); + multi_parser.print_token(multi_parser.token_text); + multi_parser.current_mode = 'CONTENT'; + break; + case 'TK_TAG_SINGLE': + multi_parser.print_newline(false, multi_parser.output); + multi_parser.print_token(multi_parser.token_text); + multi_parser.current_mode = 'CONTENT'; + break; + case 'TK_CONTENT': + if (multi_parser.token_text !== '') { + multi_parser.print_newline(false, multi_parser.output); + multi_parser.print_token(multi_parser.token_text); + } + multi_parser.current_mode = 'TAG'; + break; + } + multi_parser.last_token = multi_parser.token_type; + multi_parser.last_text = multi_parser.token_text; + } + return multi_parser.output.join(''); + } + return function(data) { + var dataHolder = ['__dataHolder_', [Math.random(), Math.random(), Math.random(), Math.random()].join('_').replace(/[^0-9]/g, '_'), '_'].join('_'); + var dataHolders = {}; + var index = 0; + data = data.replace(/(\")(data:[^\"]*)(\")/g, + function($0, $1, $2, $3) { + var name = dataHolder + index++; + dataHolders[name] = $2; + return $1 + name + $3; + }) + data = style_html(data, 2, ' ', 0x10000000); + data = data.replace(new RegExp(dataHolder + '[0-9]+', 'g'), + function($0) { + return dataHolders[$0]; + }); + return data; + } +})(); + +export default format diff --git a/packages/ui/certd-client/src/components/index.ts b/packages/ui/certd-client/src/components/index.ts new file mode 100644 index 00000000..408edf28 --- /dev/null +++ b/packages/ui/certd-client/src/components/index.ts @@ -0,0 +1,7 @@ +import { defineAsyncComponent } from "vue"; +const AsyncHighLight = defineAsyncComponent(() => import("./highlight/index.vue")); +export default { + install(app) { + app.component("FsHighlight", AsyncHighLight); + } +}; diff --git a/packages/ui/certd-client/src/i18n/index.ts b/packages/ui/certd-client/src/i18n/index.ts new file mode 100644 index 00000000..015c3545 --- /dev/null +++ b/packages/ui/certd-client/src/i18n/index.ts @@ -0,0 +1,27 @@ +import { createI18n } from "vue-i18n"; +// +import enFsLocale from "@fast-crud/fast-crud/dist/locale/lang/en.js"; +import zhFsLocale from "@fast-crud/fast-crud/dist/locale/lang/zh-cn.js"; +import en from "./locale/en"; +import zh from "./locale/zh_CN"; +const messages = { + en: { + label: "English", + // 定义您自己的字典,但是请不要和 `fs` 重复,这样会导致 fast-crud 内部组件的翻译失效. + fs: enFsLocale.fs, + ...en + }, + "zh-cn": { + label: "简体中文", + // 定义您自己的字典,但是请不要和 `fs` 重复,这样会导致 fast-crud 内部组件的翻译失效. + fs: zhFsLocale.fs, + ...zh + } +}; + +export default createI18n({ + legacy: false, + locale: "zh-cn", + fallbackLocale: "zh-cn", + messages +}); diff --git a/packages/ui/certd-client/src/i18n/locale/en.ts b/packages/ui/certd-client/src/i18n/locale/en.ts new file mode 100644 index 00000000..d59a415d --- /dev/null +++ b/packages/ui/certd-client/src/i18n/locale/en.ts @@ -0,0 +1,3 @@ +export default { + app: { crud: { i18n: { name: "name", city: "city", status: "status" } } } +}; diff --git a/packages/ui/certd-client/src/i18n/locale/zh_CN.ts b/packages/ui/certd-client/src/i18n/locale/zh_CN.ts new file mode 100644 index 00000000..cfb247c3 --- /dev/null +++ b/packages/ui/certd-client/src/i18n/locale/zh_CN.ts @@ -0,0 +1,9 @@ +export default { + app: { + crud: { i18n: { name: "姓名", city: "城市", status: "状态" } }, + login: { + logoutTip: "确认", + logoutMessage: "确定要注销登录吗?" + } + } +}; diff --git a/packages/ui/certd-client/src/layout/components/contextmenu/components/contentmenuList/index.vue b/packages/ui/certd-client/src/layout/components/contextmenu/components/contentmenuList/index.vue new file mode 100644 index 00000000..6e3866f7 --- /dev/null +++ b/packages/ui/certd-client/src/layout/components/contextmenu/components/contentmenuList/index.vue @@ -0,0 +1,56 @@ + + + + + diff --git a/packages/ui/certd-client/src/layout/components/contextmenu/index.vue b/packages/ui/certd-client/src/layout/components/contextmenu/index.vue new file mode 100644 index 00000000..664f4132 --- /dev/null +++ b/packages/ui/certd-client/src/layout/components/contextmenu/index.vue @@ -0,0 +1,68 @@ + + + + + diff --git a/packages/ui/certd-client/src/layout/components/locale/index.vue b/packages/ui/certd-client/src/layout/components/locale/index.vue new file mode 100644 index 00000000..87f8d92a --- /dev/null +++ b/packages/ui/certd-client/src/layout/components/locale/index.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/packages/ui/certd-client/src/layout/components/menu/index.jsx b/packages/ui/certd-client/src/layout/components/menu/index.jsx new file mode 100644 index 00000000..cb2cb58d --- /dev/null +++ b/packages/ui/certd-client/src/layout/components/menu/index.jsx @@ -0,0 +1,224 @@ +import { useRoute, useRouter } from "vue-router"; +import { ref, watch, onMounted, onUnmounted, resolveComponent, nextTick, defineComponent } from "vue"; +import getEachDeep from "deepdash-es/getEachDeep"; +import _ from "lodash-es"; +import BScroll from "better-scroll"; +import "./index.less"; +const eachDeep = getEachDeep(_); + +function useBetterScroll(enabled = true) { + let bsRef = ref(null); + let asideMenuRef = ref(); + + let onOpenChange = () => {}; + if (enabled) { + function bsInit() { + if (asideMenuRef.value == null) { + return; + } + bsRef.value = new BScroll(asideMenuRef.value, { + mouseWheel: true, + click: true, + momentum: false, + // 如果你愿意可以打开显示滚动条 + scrollbar: { + fade: true, + interactive: false + }, + bounce: false + }); + } + + function bsDestroy() { + if (bsRef.value != null && bsRef.value.destroy) { + try { + bsRef.value.destroy(); + } catch (e) { + // console.error(e); + } finally { + bsRef.value = null; + } + } + } + + onMounted(() => { + bsInit(); + }); + + onUnmounted(() => { + bsDestroy(); + }); + onOpenChange = async () => { + console.log("onOpenChange"); + setTimeout(() => { + bsRef.value?.refresh(); + }, 300); + }; + } + return { + onOpenChange, + asideMenuRef + }; +} +export default defineComponent({ + name: "FsMenu", + inheritAttrs: true, + props: { + menus: {}, + expandSelected: { + default: false + }, + scroll: {} + }, + setup(props, ctx) { + async function open(path) { + if (path == null) { + return; + } + if (path.startsWith("http://") || path.startsWith("https://")) { + window.open(path); + return; + } + try { + const navigationResult = await router.push(path); + if (navigationResult) { + // 导航被阻止 + } else { + // 导航成功 (包括重新导航的情况) + } + } catch (e) { + console.error("导航失败", e); + } + } + function onSelect(item) { + open(item.key); + } + + const FsIcon = resolveComponent("FsIcon"); + + const buildMenus = (children) => { + const slots = []; + if (children == null) { + return slots; + } + for (let sub of children) { + const title = () => { + if (sub?.meta?.icon) { + return ( +
+ + {sub.title} +
+ ); + } + return sub.title; + }; + if (sub.children && sub.children.length > 0) { + // eslint-disable-next-line @typescript-eslint/no-unused-vars + const subSlots = { + default: () => { + return buildMenus(sub.children); + }, + title + }; + function onTitleClick() { + if (sub.path && ctx.attrs.mode === "horizontal") { + open(sub.path); + } + } + slots.push(); + } else { + slots.push( + + {title} + + ); + } + } + return slots; + }; + const slots = { + default() { + return buildMenus(props.menus); + } + }; + const selectedKeys = ref([]); + const openKeys = ref([]); + const route = useRoute(); + const router = useRouter(); + + function openSelectedParents(fullPath) { + if (!props.expandSelected) { + return; + } + if (props.menus == null) { + return; + } + const keys = []; + let changed = false; + eachDeep(props.menus, (value, key, parent, context) => { + if (value == null) { + return; + } + if (value.path === fullPath) { + _.forEach(context.parents, (item) => { + if (item.value instanceof Array) { + return; + } + keys.push(item.value.index); + }); + } + }); + if (keys.length > 0) { + for (let key of keys) { + if (openKeys.value.indexOf(key) === -1) { + openKeys.value.push(key); + changed = true; + } + } + } + return changed; + } + + const { asideMenuRef, onOpenChange } = useBetterScroll(props.scroll); + + watch( + () => { + return route.fullPath; + }, + (path) => { + // path = route.fullPath; + selectedKeys.value = [path]; + const changed = openSelectedParents(path); + if (changed) { + onOpenChange(); + } + }, + { + immediate: true + } + ); + return () => { + const menu = ( + + ); + const classNames = { "fs-menu-wrapper": true, "fs-menu-better-scroll": props.scroll }; + return ( +
+ {menu} +
+ ); + }; + } +}); diff --git a/packages/ui/certd-client/src/layout/components/menu/index.less b/packages/ui/certd-client/src/layout/components/menu/index.less new file mode 100644 index 00000000..9521a407 --- /dev/null +++ b/packages/ui/certd-client/src/layout/components/menu/index.less @@ -0,0 +1,11 @@ +.fs-menu-wrapper{ + height: 100%; + overflow-y: auto; + &.fs-menu-better-scroll{ + overflow-y: hidden; + } + .menu-item-title{ + display: flex; + align-items: center; + } +} diff --git a/packages/ui/certd-client/src/layout/components/source-link/index.vue b/packages/ui/certd-client/src/layout/components/source-link/index.vue new file mode 100644 index 00000000..9d16a502 --- /dev/null +++ b/packages/ui/certd-client/src/layout/components/source-link/index.vue @@ -0,0 +1,54 @@ + + + + + diff --git a/packages/ui/certd-client/src/layout/components/tabs/index.vue b/packages/ui/certd-client/src/layout/components/tabs/index.vue new file mode 100644 index 00000000..21ddddb8 --- /dev/null +++ b/packages/ui/certd-client/src/layout/components/tabs/index.vue @@ -0,0 +1,295 @@ + + + + diff --git a/packages/ui/certd-client/src/layout/components/theme/color-picker.vue b/packages/ui/certd-client/src/layout/components/theme/color-picker.vue new file mode 100644 index 00000000..599baf34 --- /dev/null +++ b/packages/ui/certd-client/src/layout/components/theme/color-picker.vue @@ -0,0 +1,101 @@ + + + + diff --git a/packages/ui/certd-client/src/layout/components/theme/index.vue b/packages/ui/certd-client/src/layout/components/theme/index.vue new file mode 100644 index 00000000..bc8a92c0 --- /dev/null +++ b/packages/ui/certd-client/src/layout/components/theme/index.vue @@ -0,0 +1,51 @@ + + + + + diff --git a/packages/ui/certd-client/src/layout/components/user-info/index.vue b/packages/ui/certd-client/src/layout/components/user-info/index.vue new file mode 100644 index 00000000..24af1985 --- /dev/null +++ b/packages/ui/certd-client/src/layout/components/user-info/index.vue @@ -0,0 +1,40 @@ + + diff --git a/packages/ui/certd-client/src/layout/layout-framework.vue b/packages/ui/certd-client/src/layout/layout-framework.vue new file mode 100644 index 00000000..0e57eab8 --- /dev/null +++ b/packages/ui/certd-client/src/layout/layout-framework.vue @@ -0,0 +1,230 @@ + + + + diff --git a/packages/ui/certd-client/src/layout/layout-outside.vue b/packages/ui/certd-client/src/layout/layout-outside.vue new file mode 100644 index 00000000..a35b8c5e --- /dev/null +++ b/packages/ui/certd-client/src/layout/layout-outside.vue @@ -0,0 +1,154 @@ + + + + diff --git a/packages/ui/certd-client/src/layout/layout-pass.vue b/packages/ui/certd-client/src/layout/layout-pass.vue new file mode 100644 index 00000000..98240aef --- /dev/null +++ b/packages/ui/certd-client/src/layout/layout-pass.vue @@ -0,0 +1,3 @@ + diff --git a/packages/ui/certd-client/src/main.ts b/packages/ui/certd-client/src/main.ts new file mode 100644 index 00000000..409b9ee6 --- /dev/null +++ b/packages/ui/certd-client/src/main.ts @@ -0,0 +1,23 @@ +import { createApp } from "vue"; +import App from "./App.vue"; +import router from "./router"; +import Antd from "ant-design-vue"; +import "ant-design-vue/dist/antd.less"; +// import "virtual:windi.css"; +import "./style/common.less"; +import "./mock"; +import i18n from "./i18n"; +import store from "./store"; +import components from "./components"; +import plugin from "./plugin/"; + +// @ts-ignore +const app = createApp(App); +// 尽量 +app.use(Antd); +app.use(router); +app.use(i18n); +app.use(store); +app.use(components); +app.use(plugin, { i18n }); +app.mount("#app"); diff --git a/packages/ui/certd-client/src/mock/base.js b/packages/ui/certd-client/src/mock/base.js new file mode 100644 index 00000000..1cacbac7 --- /dev/null +++ b/packages/ui/certd-client/src/mock/base.js @@ -0,0 +1,280 @@ +import _ from "lodash-es"; +function copyList(originList, newList, options, parentId) { + for (const item of originList) { + const newItem = { ...item, parentId }; + newItem.id = ++options.idGenerator; + newList.push(newItem); + if (item.children != null) { + newItem.children = []; + copyList(item.children, newItem.children, options, newItem.id); + } + } +} + +function delById(req, list) { + for (let i = 0; i < list.length; i++) { + const item = list[i]; + console.log("remove i", i, req, req.params.id, item.id); + if (item.id === parseInt(req.params.id)) { + console.log("remove i", i); + list.splice(i, 1); + break; + } + if (item.children != null && item.children.length > 0) { + delById(req, item.children); + } + } +} + +function findById(id, list) { + for (const item of list) { + if (item.id === id) { + return item; + } + if (item.children != null && item.children.length > 0) { + const sub = findById(id, item.children); + if (sub != null) { + return sub; + } + } + } +} +export default { + findById, + buildMock(options) { + const name = options.name; + if (options.copyTimes == null) { + options.copyTimes = 29; + } + const list = []; + for (let i = 0; i < options.copyTimes; i++) { + copyList(options.list, list, options); + } + options.list = list; + return [ + { + path: "/mock/" + name + "/page", + method: "get", + handle(req) { + let data = [...list]; + let limit = 20; + let offset = 0; + for (const item of list) { + if (item.children != null && item.children.length === 0) { + item.hasChildren = false; + item.lazy = false; + } + } + let orderProp, orderAsc; + if (req && req.body) { + const { page, query, sort } = req.body; + if (page.limit != null) { + limit = parseInt(page.limit); + } + if (page.offset != null) { + offset = parseInt(page.offset); + } + orderProp = sort.prop; + orderAsc = sort.asc; + + if (Object.keys(query).length > 0) { + data = list.filter((item) => { + let allFound = true; // 是否所有条件都符合 + for (const key in query) { + // 判定某一个条件 + const value = query[key]; + if (value == null || value === "") { + continue; + } + if (value instanceof Array) { + // 如果条件中的value是数组的话,只要查到一个就行 + if (value.length === 0) { + continue; + } + let found = false; + for (const i of value) { + if (item[key] instanceof Array) { + for (const j of item[key]) { + if (i === j) { + found = true; + break; + } + } + if (found) { + break; + } + } else if (item[key] === i || (typeof item[key] === "string" && item[key].indexOf(i + "") >= 0)) { + found = true; + break; + } + if (found) { + break; + } + } + if (!found) { + allFound = false; + } + } else if (value instanceof Object) { + for (const key2 in value) { + const v = value[key2]; + if (v && item[key] && v !== item[key][key2]) { + return false; + } + } + } else if (item[key] !== value) { + allFound = false; + } + } + return allFound; + }); + } + } + + const start = offset; + let end = offset + limit; + if (data.length < end) { + end = data.length; + } + + if (orderProp) { + // 排序 + data.sort((a, b) => { + let ret = 0; + if (a[orderProp] > b[orderProp]) { + ret = 1; + } else { + ret = -1; + } + return orderAsc ? ret : -ret; + }); + } + + const records = data.slice(start, end); + const lastOffset = data.length - (data.length % limit); + if (offset > lastOffset) { + offset = lastOffset; + } + return { + code: 0, + msg: "success", + data: { + records: records, + total: data.length, + limit, + offset + } + }; + } + }, + { + path: "/mock/" + name + "/get", + method: "get", + handle(req) { + let id = req.params.id; + id = parseInt(id); + let current = null; + for (const item of list) { + if (item.id === id) { + current = item; + break; + } + } + return { + code: 0, + msg: "success", + data: current + }; + } + }, + { + path: "/mock/" + name + "/add", + method: "post", + handle(req) { + req.body.id = ++options.idGenerator; + list.unshift(req.body); + return { + code: 0, + msg: "success", + data: req.body.id + }; + } + }, + { + path: "/mock/" + name + "/update", + method: "post", + handle(req) { + const item = findById(req.body.id, list); + if (item) { + _.mergeWith(item, req.body, (objValue, srcValue) => { + if (srcValue == null) { + return; + } + // 如果被合并对象为数组,则直接被覆盖对象覆盖,只要覆盖对象不为空 + if (_.isArray(objValue)) { + return srcValue; + } + }); + } + return { + code: 0, + msg: "success", + data: null + }; + } + }, + { + path: "/mock/" + name + "/delete", + method: "post", + handle(req) { + delById(req, list); + return { + code: 0, + msg: "success", + data: null + }; + } + }, + { + path: "/mock/" + name + "/batchDelete", + method: "post", + handle(req) { + const ids = req.body.ids; + for (let i = list.length - 1; i >= 0; i--) { + const item = list[i]; + if (ids.indexOf(item.id) >= 0) { + list.splice(i, 1); + } + } + return { + code: 0, + msg: "success", + data: null + }; + } + }, + { + path: "/mock/" + name + "/delete", + method: "post", + handle(req) { + delById(req, list); + return { + code: 0, + msg: "success", + data: null + }; + } + }, + { + path: "/mock/" + name + "/all", + method: "post", + handle(req) { + return { + code: 0, + msg: "success", + data: list + }; + } + } + ]; + } +}; diff --git a/packages/ui/certd-client/src/mock/common/cascader-data.js b/packages/ui/certd-client/src/mock/common/cascader-data.js new file mode 100644 index 00000000..2b22016f --- /dev/null +++ b/packages/ui/certd-client/src/mock/common/cascader-data.js @@ -0,0 +1,268 @@ +export default [ + { + value: "zhinan", + label: "指南", + children: [ + { + value: "shejiyuanze", + label: "设计原则", + children: [ + { + value: "yizhi", + label: "一致" + }, + { + value: "fankui", + label: "反馈" + }, + { + value: "xiaolv", + label: "效率" + }, + { + value: "kekong", + label: "可控" + } + ] + }, + { + value: "daohang", + label: "导航", + children: [ + { + value: "cexiangdaohang", + label: "侧向导航" + }, + { + value: "dingbudaohang", + label: "顶部导航" + } + ] + } + ] + }, + { + value: "zujian", + label: "组件", + children: [ + { + value: "basic", + label: "Basic", + children: [ + { + value: "layout", + label: "Layout 布局" + }, + { + value: "color", + label: "Color 色彩" + }, + { + value: "typography", + label: "Typography 字体" + }, + { + value: "icon", + label: "Icon 图标" + }, + { + value: "button", + label: "Button 按钮" + } + ] + }, + { + value: "form", + label: "Form", + children: [ + { + value: "radio", + label: "Radio 单选框" + }, + { + value: "checkbox", + label: "Checkbox 多选框" + }, + { + value: "input", + label: "Input 输入框" + }, + { + value: "input-number", + label: "InputNumber 计数器" + }, + { + value: "select", + label: "Select 选择器" + }, + { + value: "cascader", + label: "Cascader 级联选择器" + }, + { + value: "switch", + label: "Switch 开关" + }, + { + value: "slider", + label: "Slider 滑块" + }, + { + value: "time-picker", + label: "TimePicker 时间选择器" + }, + { + value: "date-picker", + label: "DatePicker 日期选择器" + }, + { + value: "datetime-picker", + label: "DateTimePicker 日期时间选择器" + }, + { + value: "upload", + label: "Upload 上传" + }, + { + value: "rate", + label: "Rate 评分" + }, + { + value: "form1", + label: "Form 表单" + } + ] + }, + { + value: "data", + label: "Data", + children: [ + { + value: "table", + label: "Table 表格" + }, + { + value: "tag", + label: "Tag 标签" + }, + { + value: "progress", + label: "Progress 进度条" + }, + { + value: "tree", + label: "Tree 树形控件" + }, + { + value: "pagination", + label: "Pagination 分页" + }, + { + value: "badge", + label: "Badge 标记" + } + ] + }, + { + value: "notice", + label: "Notice", + children: [ + { + value: "alert", + label: "Alert 警告" + }, + { + value: "loading", + label: "Loading 加载" + }, + { + value: "message", + label: "Message 消息提示" + }, + { + value: "message-box", + label: "MessageBox 弹框" + }, + { + value: "notification", + label: "Notification 通知" + } + ] + }, + { + value: "navigation", + label: "Navigation", + children: [ + { + value: "menu", + label: "NavMenu 导航菜单" + }, + { + value: "tabs", + label: "Tabs 标签页" + }, + { + value: "breadcrumb", + label: "Breadcrumb 面包屑" + }, + { + value: "dropdown", + label: "Dropdown 下拉菜单" + }, + { + value: "steps", + label: "Steps 步骤条" + } + ] + }, + { + value: "others", + label: "Others", + children: [ + { + value: "dialog", + label: "Dialog 对话框" + }, + { + value: "tooltip", + label: "Tooltip 文字提示" + }, + { + value: "popover", + label: "Popover 弹出框" + }, + { + value: "card", + label: "Card 卡片" + }, + { + value: "carousel", + label: "Carousel 走马灯" + }, + { + value: "collapse", + label: "Collapse 折叠面板" + } + ] + } + ] + }, + { + value: "ziyuan", + label: "资源", + children: [ + { + value: "axure", + label: "Axure Components" + }, + { + value: "sketch", + label: "Sketch Templates" + }, + { + value: "jiaohu", + label: "组件交互文档" + } + ] + } +]; diff --git a/packages/ui/certd-client/src/mock/common/mock.dict.js b/packages/ui/certd-client/src/mock/common/mock.dict.js new file mode 100644 index 00000000..d758ddd4 --- /dev/null +++ b/packages/ui/certd-client/src/mock/common/mock.dict.js @@ -0,0 +1,123 @@ +import cascaderData from "./cascader-data"; +import pcaDataLittle from "./pca-data-little"; +import { TreeNodesLazyLoader, getPcaData } from "./pcas-data"; + +const openStatus = [ + { value: "1", label: "打开", color: "success",icon:"ion:radio-button-on" }, + { value: "2", label: "停止", color: "cyan" }, + { value: "0", label: "关闭", color: "red",icon:"ion:radio-button-off" } +]; + +const moreOpenStatus = [ + { value: "1", label: "打开(open)", color: "success" }, + { value: "2", label: "停止(stop)", color: "cyan" }, + { value: "0", label: "关闭(close)", color: "red" } +]; + +const textStatus = [ + { id: "1", text: "打开", color: "success" }, + { id: "2", text: "停止", color: "cyan" }, + { id: "0", text: "关闭", color: "red" } +]; + +export function GetTreeChildrenByParentId(parentId) { + return TreeNodesLazyLoader.getChildren(parentId); +} + +export function GetNodesByValues(values) { + return TreeNodesLazyLoader.getNodesByValues(values); +} + +export default [ + { + path: "/mock/dicts/OpenStatusEnum", + method: "get", + handle() { + return { + code: 0, + msg: "success", + data: openStatus + }; + } + }, + { + path: "/mock/dicts/_OpenStatusEnum2", + method: "get", + handle() { + return { + code: 0, + msg: "success", + data: textStatus + }; + } + }, + { + path: "/mock/dicts/moreOpenStatusEnum", + method: "get", + handle() { + return { + code: 0, + msg: "success", + data: moreOpenStatus + }; + } + }, + { + path: "/mock/dicts/cascaderData", + method: "get", + handle() { + return { + code: 0, + msg: "success", + data: cascaderData + }; + } + }, + { + path: "/mock/dicts/pca", + method: "get", + async handle() { + const data = await getPcaData(); + return { + code: 0, + msg: "success", + data: data + }; + } + }, + { + path: "/mock/dicts/littlePca", + method: "get", + async handle() { + return { + code: 0, + msg: "success", + data: pcaDataLittle + }; + } + }, + { + path: "/mock/tree/GetTreeChildrenByParentId", + method: "get", + async handle({ params }) { + const list = await GetTreeChildrenByParentId(params.parentId); + return { + code: 0, + msg: "success", + data: list + }; + } + }, + { + path: "/mock/tree/GetNodesByValues", + method: "get", + async handle({ params }) { + const list = await GetNodesByValues(params.values); + return { + code: 0, + msg: "success", + data: list + }; + } + } +]; diff --git a/packages/ui/certd-client/src/mock/common/pca-data-little.js b/packages/ui/certd-client/src/mock/common/pca-data-little.js new file mode 100644 index 00000000..ae5aa367 --- /dev/null +++ b/packages/ui/certd-client/src/mock/common/pca-data-little.js @@ -0,0 +1,70 @@ +export default [ + { + code: "1", + name: "北京", + children: [ + { + code: "2", + name: "北京市区", + children: [ + { + code: "3", + name: "海淀" + }, + { + code: "4", + name: "朝阳" + } + ] + }, + { + code: "5", + name: "北京郊区", + children: [ + { + code: "6", + name: "海淀郊区" + }, + { + code: "7", + name: "朝阳郊区" + } + ] + } + ] + }, + { + code: "11", + name: "深圳", + children: [ + { + code: "12", + name: "深圳市区", + children: [ + { + code: "13", + name: "南山" + }, + { + code: "14", + name: "福田" + } + ] + }, + { + code: "15", + name: "深圳郊区", + children: [ + { + code: "16", + name: "南山郊区" + }, + { + code: "17", + name: "福田郊区" + } + ] + } + ] + } +]; diff --git a/packages/ui/certd-client/src/mock/common/pcas-data.js b/packages/ui/certd-client/src/mock/common/pcas-data.js new file mode 100644 index 00000000..c1bbb64a --- /dev/null +++ b/packages/ui/certd-client/src/mock/common/pcas-data.js @@ -0,0 +1,87 @@ +import _ from "lodash-es"; +export async function getPcasData() { + const pcasData = () => import("china-division/dist/pcas-code.json"); + const ret = await pcasData(); + return ret.default; +} +export async function getPcaData() { + const pcaData = () => import("china-division/dist/pca-code.json"); + const ret = await pcaData(); + return ret.default; +} +export const TreeNodesLazyLoader = { + getNodesByValues(values) { + console.log("getNodesByValues", values); + if (!(values instanceof Array)) { + values = [values]; + } + return getPcasData().then((data) => { + const nodes = []; + for (const value of values) { + const found = this.getNode(data, value); + if (found) { + const target = _.cloneDeep(found); + delete target.children; + nodes.push(target); + } + } + return nodes; + }); + }, + getNode(list, value) { + for (const item of list) { + if (item.code === value) { + return item; + } + if (item.children && item.children.length > 0) { + const found = this.getNode(item.children, value); + if (found) { + return found; + } + } + } + }, + getChildren(parent) { + return getPcasData().then((data) => { + const list = this.getChildrenByParent(parent, data); + if (list == null) { + return []; + } + return this.cloneAndDeleteChildren(list); + }); + }, + getChildrenByParent(parentId, tree) { + if (!parentId) { + // 取第一级 + return tree; + } else { + for (const node of tree) { + if (node.code === parentId) { + return node.children; + } + if (node.children && node.children.length > 0) { + // 递归查找 + const list = this.getChildrenByParent(parentId, node.children); + if (list) { + return list; + } + } + } + } + }, + cloneAndDeleteChildren(list) { + const newList = []; + for (const node of list) { + const newNode = {}; + Object.assign(newNode, node); + if (newNode.children == null || newNode.children.length === 0) { + newNode.isLeaf = true; + newNode.leaf = true; + } + delete newNode.children; + newList.push(newNode); + } + console.log("found children:", newList); + return newList; + } +}; diff --git a/packages/ui/certd-client/src/mock/index.js b/packages/ui/certd-client/src/mock/index.js new file mode 100644 index 00000000..4494fc5f --- /dev/null +++ b/packages/ui/certd-client/src/mock/index.js @@ -0,0 +1,49 @@ +import { mock } from "../api/service"; +import * as tools from "../api/tools"; +import _ from "lodash-es"; +const commonMocks = import.meta.globEager("./common/mock.*.js"); +const apiMocks = import.meta.globEager("../api/modules/*.mock.ts"); +const viewMocks = import.meta.globEager("../views/**/mock.js"); + +const list = []; +_.forEach(commonMocks, (value) => { + list.push(value.default); +}); +_.forEach(apiMocks, (value) => { + list.push(value.default); +}); +_.forEach(viewMocks, (value) => { + list.push(value.default); +}); + +list.forEach((apiFile) => { + for (const item of apiFile) { + mock.onAny(new RegExp(item.path)).reply(async (config) => { + console.log("------------fake request start -------------"); + console.log("request:", config); + const data = config.data ? JSON.parse(config.data) : {}; + const query = config.url.indexOf("?") >= 0 ? config.url.substring(config.url.indexOf("?") + 1) : undefined; + const params = config.params || {}; + if (query) { + const arr = query.split("&"); + for (const item of arr) { + const kv = item.split("="); + params[kv[0]] = kv[1]; + } + } + + const req = { + body: data, + params: params + }; + const ret = await item.handle(req); + console.log("response:", ret); + console.log("------------fake request end-------------"); + if (ret.code === 0) { + return tools.responseSuccess(ret.data, ret.msg); + } else { + return tools.responseError(ret.data, ret.msg, ret.code); + } + }); + } +}); diff --git a/packages/ui/certd-client/src/plugin/fast-crud/index.tsx b/packages/ui/certd-client/src/plugin/fast-crud/index.tsx new file mode 100644 index 00000000..5733f18d --- /dev/null +++ b/packages/ui/certd-client/src/plugin/fast-crud/index.tsx @@ -0,0 +1,245 @@ +import { request, requestForMock } from "/src/api/service"; +import "/src/mock"; +import { FastCrud, UseCrudProps, useTypes, setLogger, useColumns, ColumnCompositionProps, MergeColumnPlugin, CrudOptions } from "@fast-crud/fast-crud"; +import "@fast-crud/fast-crud/dist/style.css"; +import { FsExtendsUploader, FsExtendsEditor, FsExtendsJson, FsExtendsCopyable, FsExtendsTime } from "@fast-crud/fast-extends"; +import "@fast-crud/fast-extends/dist/style.css"; +import UiAntdv from "@fast-crud/ui-antdv"; +import _ from "lodash-es"; +import { useCrudPermission } from "../permission"; + +function install(app, options: any = {}) { + app.use(UiAntdv); + //设置日志级别 + setLogger({ level: "debug" }); + app.use(FastCrud, { + i18n: options.i18n, + async dictRequest({ url }) { + if (url && url.startsWith("/mock")) { + //如果是crud开头的dict请求视为mock + return await requestForMock({ url, method: "post" }); + } + return await request({ url, method: "post" }); + }, + /** + * useCrud时会被执行 + * @param context,useCrud的参数 + */ + commonOptions(context: UseCrudProps) { + const crudBinding = context.expose?.crudBinding; + const opts: CrudOptions = { + table: { + size: "small", + pagination: false, + onResizeColumn: (w, col) => { + crudBinding.value.table.columnsMap[col.key].width = w; + } + }, + rowHandle: { + buttons: { + view: { type: "link", text: null, icon: "ion:eye-outline" }, + edit: { type: "link", text: null, icon: "ion:create-outline" }, + remove: { type: "link", style: { color: "red" }, text: null, icon: "ion:trash-outline" } + }, + dropdown: { + more: { + type: "link" + } + } + }, + request: { + transformQuery: ({ page, form, sort }) => { + const limit = page.pageSize; + const currentPage = page.currentPage ?? 1; + const offset = limit * (currentPage - 1); + + sort = sort == null ? {} : sort; + + return { + page: { + limit, + offset + }, + query: form, + sort + }; + }, + transformRes: ({ res }) => { + const pageSize = res.limit; + let currentPage = res.offset / pageSize; + if (res.offset % pageSize === 0) { + currentPage++; + } + return { currentPage, pageSize, ...res }; + } + }, + form: { + display: "flex", + labelCol: { + //固定label宽度 + span: null, + style: { + width: "120px" + } + }, + wrapperCol: { + span: null + } + } + }; + + // 从 useCrud({permission}) 里获取permission参数,去设置各个按钮的权限 + const crudPermission = useCrudPermission({ permission: context.permission }); + return crudPermission.merge(opts); + } + }); + + // fast-extends里面的扩展组件均为异步组件,只有在使用时才会被加载,并不会影响首页加载速度 + //安装uploader 公共参数 + app.use(FsExtendsUploader, { + defaultType: "cos", + cos: { + domain: "https://d2p-demo-1251260344.cos.ap-guangzhou.myqcloud.com", + bucket: "d2p-demo-1251260344", + region: "ap-guangzhou", + secretId: "", // + secretKey: "", // 传了secretKey 和secretId 代表使用本地签名模式(不安全,生产环境不推荐) + getAuthorization(custom) { + // 不传secretKey代表使用临时签名模式,此时此参数必传(安全,生产环境推荐) + return request({ + url: "http://www.docmirror.cn:7070/api/upload/cos/getAuthorization", + method: "get" + }).then((ret) => { + // 返回结构如下 + // ret.data:{ + // TmpSecretId, + // TmpSecretKey, + // XCosSecurityToken, + // ExpiredTime, // SDK 在 ExpiredTime 时间前,不会再次调用 getAuthorization + // } + return ret; + }); + }, + successHandle(ret) { + // 上传完成后可以在此处处理结果,修改url什么的 + console.log("success handle:", ret); + return ret; + } + }, + alioss: { + domain: "https://d2p-demo.oss-cn-shenzhen.aliyuncs.com", + bucket: "d2p-demo", + region: "oss-cn-shenzhen", + accessKeyId: "", + accessKeySecret: "", + async getAuthorization(custom, context) { + // 不传accessKeySecret代表使用临时签名模式,此时此参数必传(安全,生产环境推荐) + const ret = await request({ + url: "http://www.docmirror.cn:7070/api/upload/alioss/getAuthorization", + method: "get" + }); + console.log("ret", ret); + return ret; + }, + sdkOpts: { + // sdk配置 + secure: true // 默认为非https上传,为了安全,设置为true + }, + successHandle(ret) { + // 上传完成后可以在此处处理结果,修改url什么的 + console.log("success handle:", ret); + return ret; + } + }, + qiniu: { + bucket: "d2p-demo", + async getToken(options) { + const ret = await request({ + url: "http://www.docmirror.cn:7070/api/upload/qiniu/getToken", + method: "get" + }); + return ret; // {token:xxx,expires:xxx} + }, + successHandle(ret) { + // 上传完成后可以在此处处理结果,修改url什么的 + console.log("success handle:", ret); + return ret; + }, + domain: "http://d2p.file.handsfree.work/" + }, + form: { + action: "http://www.docmirror.cn:7070/api/upload/form/upload", + name: "file", + withCredentials: false, + uploadRequest: async ({ action, file, onProgress }) => { + // @ts-ignore + const data = new FormData(); + data.append("file", file); + return await request({ + url: action, + method: "post", + headers: { + "Content-Type": "multipart/form-data" + }, + timeout: 60000, + data, + onUploadProgress: (p) => { + onProgress({ percent: Math.round((p.loaded / p.total) * 100) }); + } + }); + }, + successHandle(ret) { + // 上传完成后的结果处理, 此处应返回格式为{url:xxx} + return { + url: "http://www.docmirror.cn:7070" + ret, + key: ret.replace("/api/upload/form/download?key=", "") + }; + } + } + }); + + //安装editor + app.use(FsExtendsEditor, { + //编辑器的公共配置 + wangEditor: {} + }); + app.use(FsExtendsJson); + app.use(FsExtendsTime); + app.use(FsExtendsCopyable); + + // 此处演示自定义字段类型 + const { addTypes } = useTypes(); + addTypes({ + time2: { + //如果与官方字段类型同名,将会覆盖官方的字段类型 + form: { component: { name: "a-date-picker" } }, + column: { component: { name: "fs-date-format", format: "YYYY-MM-DD" } }, + valueBuilder(context) { + console.log("time2,valueBuilder", context); + } + } + }); + + // 此处演示自定义字段合并插件 + const { registerMergeColumnPlugin } = useColumns(); + registerMergeColumnPlugin({ + name: "readonly-plugin", + order: 1, + handle: (columnProps: ColumnCompositionProps) => { + // 你可以在此处做你自己的处理 + // 比如你可以定义一个readonly的公共属性,处理该字段只读,不能编辑 + if (columnProps.readonly) { + // 合并column配置 + _.merge(columnProps, { + form: { show: false }, + viewForm: { show: true } + }); + } + return columnProps; + } + }); +} + +export default { + install +}; diff --git a/packages/ui/certd-client/src/plugin/iconfont/iconfont.js b/packages/ui/certd-client/src/plugin/iconfont/iconfont.js new file mode 100644 index 00000000..357dc3bd --- /dev/null +++ b/packages/ui/certd-client/src/plugin/iconfont/iconfont.js @@ -0,0 +1 @@ +!function(t){var e,c,o,n,l,a='',i=(i=document.getElementsByTagName("script"))[i.length-1].getAttribute("data-injectcss"),h=function(t,e){e.parentNode.insertBefore(t,e)};if(i&&!t.__iconfont__svg__cssinject__){t.__iconfont__svg__cssinject__=!0;try{document.write("")}catch(t){console&&console.log(t)}}function s(){l||(l=!0,o())}function d(){try{n.documentElement.doScroll("left")}catch(t){return void setTimeout(d,50)}s()}e=function(){var t,e=document.createElement("div");e.innerHTML=a,a=null,(e=e.getElementsByTagName("svg")[0])&&(e.setAttribute("aria-hidden","true"),e.style.position="absolute",e.style.width=0,e.style.height=0,e.style.overflow="hidden",e=e,(t=document.body).firstChild?h(e,t.firstChild):t.appendChild(e))},document.addEventListener?~["complete","loaded","interactive"].indexOf(document.readyState)?setTimeout(e,0):(c=function(){document.removeEventListener("DOMContentLoaded",c,!1),e()},document.addEventListener("DOMContentLoaded",c,!1)):document.attachEvent&&(o=e,n=t.document,l=!1,d(),n.onreadystatechange=function(){"complete"==n.readyState&&(n.onreadystatechange=null,s())})}(window); diff --git a/packages/ui/certd-client/src/plugin/iconfont/index.ts b/packages/ui/certd-client/src/plugin/iconfont/index.ts new file mode 100644 index 00000000..e1f5d7f5 --- /dev/null +++ b/packages/ui/certd-client/src/plugin/iconfont/index.ts @@ -0,0 +1 @@ +import "./iconfont.js" diff --git a/packages/ui/certd-client/src/plugin/iconify/index.ts b/packages/ui/certd-client/src/plugin/iconify/index.ts new file mode 100644 index 00000000..34aacf5a --- /dev/null +++ b/packages/ui/certd-client/src/plugin/iconify/index.ts @@ -0,0 +1,2 @@ +// import "@iconify/iconify"; +import "@purge-icons/generated"; diff --git a/packages/ui/certd-client/src/plugin/index.ts b/packages/ui/certd-client/src/plugin/index.ts new file mode 100644 index 00000000..4a73280d --- /dev/null +++ b/packages/ui/certd-client/src/plugin/index.ts @@ -0,0 +1,12 @@ +import "./iconify"; +import "./iconfont"; +import FastCrud from "./fast-crud"; +import permission from "./permission"; +function install(app, options: any = {}) { + app.use(FastCrud, options); + app.use(permission); +} + +export default { + install +}; diff --git a/packages/ui/certd-client/src/plugin/permission/api.ts b/packages/ui/certd-client/src/plugin/permission/api.ts new file mode 100644 index 00000000..2b9c1ea4 --- /dev/null +++ b/packages/ui/certd-client/src/plugin/permission/api.ts @@ -0,0 +1,10 @@ +import { request } from "/src/api/service"; +export async function getPermissions() { + const ret = await request({ + url: "/sys/authority/user/permissions", + method: "post" + }); + // 如果使用你自己的后端,需要在此处将返回结果改造为本模块需要的结构 + // 结构详情,请参考示例中打印的日志 ”获取权限数据成功:{...}“ (实际上就是“资源管理”页面中列出来的数据) + return ret; +} diff --git a/packages/ui/certd-client/src/plugin/permission/directive/index.js b/packages/ui/certd-client/src/plugin/permission/directive/index.js new file mode 100644 index 00000000..e0e5181f --- /dev/null +++ b/packages/ui/certd-client/src/plugin/permission/directive/index.js @@ -0,0 +1,9 @@ +import permission from "./permission"; +import permissionUtil from "../util.permission"; +const install = function (app) { + app.directive("permission", permission); + app.config.globalProperties.$hasPermissions = permissionUtil.hasPermissions; +}; + +permission.install = install; +export default permission; diff --git a/packages/ui/certd-client/src/plugin/permission/directive/permission.js b/packages/ui/certd-client/src/plugin/permission/directive/permission.js new file mode 100644 index 00000000..0b2a9578 --- /dev/null +++ b/packages/ui/certd-client/src/plugin/permission/directive/permission.js @@ -0,0 +1,11 @@ +import permissionUtil from "../util.permission"; +export default { + mounted(el, binding, vnode) { + const { value } = binding; + const hasPermission = permissionUtil.hasPermissions(value); + + if (!hasPermission) { + el.parentNode && el.parentNode.removeChild(el); + } + } +}; diff --git a/packages/ui/certd-client/src/plugin/permission/errors.ts b/packages/ui/certd-client/src/plugin/permission/errors.ts new file mode 100644 index 00000000..6537f454 --- /dev/null +++ b/packages/ui/certd-client/src/plugin/permission/errors.ts @@ -0,0 +1,5 @@ +export class NoPermissionError extends Error { + constructor(message?: string) { + super(message || "对不起,您没有权限执行此操作"); + } +} diff --git a/packages/ui/certd-client/src/plugin/permission/hook.ts b/packages/ui/certd-client/src/plugin/permission/hook.ts new file mode 100644 index 00000000..af4b0c76 --- /dev/null +++ b/packages/ui/certd-client/src/plugin/permission/hook.ts @@ -0,0 +1,45 @@ +import router from "/src/router"; +import { useUserStore } from "/@/store/modules/user"; +import { usePermissionStore } from "./store.permission"; +import util from "./util.permission"; +import { message } from "ant-design-vue"; +import NProgress from "nprogress"; +export function registerRouterHook() { + // 注册路由beforeEach钩子,在第一次加载路由页面时,加载权限 + router.beforeEach(async (to, from, next) => { + const permissionStore = usePermissionStore(); + if (permissionStore.isInited) { + if (to.meta.permission) { + //校验权限 + // @ts-ignore + if (!util.hasPermissions(to.meta.permission)) { + //没有权限 + message.warn("对不起,您没有权限"); + //throw new Error("对不起,您没有权限"); + NProgress.done(); + return false; + } + } + next(); + return; + } + + const userStore = useUserStore(); + const token = userStore.getToken; + if (!token || token === "undefined") { + next(); + return; + } + + // 初始化权限列表 + try { + console.log("permission is enabled"); + await permissionStore.loadFromRemote(); + console.log("PM load success"); + next({ ...to, replace: true }); + } catch (e) { + console.error("加载动态路由失败", e); + next(); + } + }); +} diff --git a/packages/ui/certd-client/src/plugin/permission/index.ts b/packages/ui/certd-client/src/plugin/permission/index.ts new file mode 100644 index 00000000..c300560a --- /dev/null +++ b/packages/ui/certd-client/src/plugin/permission/index.ts @@ -0,0 +1,23 @@ +import permissionDirective from "./directive/index"; +import { registerRouterHook } from "./hook"; +import util from "./util.permission"; +export * from "./use-crud-permission"; +export * from "./errors"; + +export function usePermission() { + return { + ...util + }; +} + +export default { + install(app) { + // 开启权限模块 + // 注册v-permission指令, 用于控制按钮权限 + app.use(permissionDirective); + // 注册路由钩子 + // 通过路由守卫,在登录成功后拦截路由,从后台加载权限数据 + // 然后将权限数据转化为菜单和路由,添加到系统中 + registerRouterHook(); + } +}; diff --git a/packages/ui/certd-client/src/plugin/permission/store.permission.ts b/packages/ui/certd-client/src/plugin/permission/store.permission.ts new file mode 100644 index 00000000..5cbb3305 --- /dev/null +++ b/packages/ui/certd-client/src/plugin/permission/store.permission.ts @@ -0,0 +1,89 @@ +import { defineStore } from "pinia"; +import { useResourceStore } from "/src/store/modules/resource"; +import { getPermissions } from "./api"; +import { mitter } from "/@/utils/util.mitt"; +import { env } from "/@/utils/util.env"; + +//监听注销事件 +mitter.on("app.logout", () => { + const permissionStore = usePermissionStore(); + permissionStore.clear(); +}); + +interface PermissionState { + permissions: []; + inited: boolean; +} + +/** + * 构建权限码列表 + * @param menuTree + * @param permissionList + * @returns {*} + */ +function formatPermissions(menuTree: Array, permissionList = []) { + if (menuTree == null) { + menuTree = []; + } + menuTree.forEach((item: any) => { + if (item.permission) { + // @ts-ignore + permissionList.push(item.permission); + } + if (item.children != null && item.children.length > 0) { + formatPermissions(item.children, permissionList); + } + }); + return permissionList; +} + +export const usePermissionStore = defineStore({ + id: "app.permission", + state: (): PermissionState => ({ + permissions: [], + inited: false + }), + getters: { + getPermissions() { + // @ts-ignore + return this.permissions; + }, + isInited() { + // @ts-ignore + return this.inited; + } + }, + actions: { + init({ permissions }) { + this.permissions = permissions; + this.inited = true; + }, + clear() { + this.permissions = []; + this.inited = false; + }, + resolve(resourceTree) { + const permissions = formatPermissions(resourceTree); + this.init({ permissions }); + + //过滤没有权限的菜单 + const resourceStore = useResourceStore(); + resourceStore.filterByPermission(permissions); + }, + async loadFromRemote() { + let permissionTree = []; + if (env.PM_ENABLED === "false") { + console.warn("当前权限模块未开启,权限列表为空"); + } else { + //开启了权限模块,向后台请求权限列表 + const data = await getPermissions(); + if (data != null) { + permissionTree = data; + } else { + console.warn("当前获取到的权限列表为空"); + } + } + this.resolve(permissionTree); + } + } +}); diff --git a/packages/ui/certd-client/src/plugin/permission/use-crud-permission.ts b/packages/ui/certd-client/src/plugin/permission/use-crud-permission.ts new file mode 100644 index 00000000..2c60f8e2 --- /dev/null +++ b/packages/ui/certd-client/src/plugin/permission/use-crud-permission.ts @@ -0,0 +1,60 @@ +import { usePermission } from "/@/plugin/permission"; +import _ from "lodash-es"; + +/** + * 设置按钮动作权限 + * @param permission {prefix,extra} + */ +export function useCrudPermission({ permission }) { + const { hasPermissions } = usePermission(); + + const prefix = permission instanceof Object ? permission.prefix : permission; + + //根据权限显示按钮 + function hasActionPermission(action) { + if (!prefix) { + return true; + } + return hasPermissions(prefix + ":" + action); + } + + function buildCrudPermission() { + if (permission == null) { + return {}; + } + + let extra = {}; + if (permission instanceof Object) { + extra = permission.extra; + if (permission.extra && permission.extra instanceof Function) { + extra = permission.extra({ hasActionPermission }); + } + } + + return _.merge( + { + actionbar: { + buttons: { + add: { show: hasActionPermission("add") } + } + }, + rowHandle: { + buttons: { + edit: { show: hasActionPermission("edit") }, + remove: { show: hasActionPermission("remove") }, + view: { show: hasActionPermission("view") } + } + } + }, + extra + ); + } + + function merge(userOptions) { + const permissionOptions = buildCrudPermission(); + _.merge(permissionOptions, userOptions); + return permissionOptions; + } + + return { merge, buildCrudPermission, hasActionPermission }; +} diff --git a/packages/ui/certd-client/src/plugin/permission/util.permission.ts b/packages/ui/certd-client/src/plugin/permission/util.permission.ts new file mode 100644 index 00000000..1c197335 --- /dev/null +++ b/packages/ui/certd-client/src/plugin/permission/util.permission.ts @@ -0,0 +1,29 @@ +import { usePermissionStore } from "./store.permission"; +import { NoPermissionError } from "./errors"; +import { message } from "ant-design-vue"; +const util = { + hasPermissions: (value: string | string[]): boolean => { + let need: string[] = []; + if (typeof value === "string") { + need.push(value); + } else if (value && value instanceof Array && value.length > 0) { + need = need.concat(value); + } + if (need.length === 0) { + throw new Error('need permissions! Like "sys:user:view" '); + } + const permissionStore = usePermissionStore(); + const userPermissionList = permissionStore.getPermissions; + return userPermissionList.some((permission) => { + return need.includes(permission); + }); + }, + requirePermissions: (value) => { + if (!util.hasPermissions(value)) { + message.error("对不起,您没有权限执行此操作"); + throw new NoPermissionError(); + } + } +}; + +export default util; diff --git a/packages/ui/certd-client/src/router/index.ts b/packages/ui/certd-client/src/router/index.ts new file mode 100644 index 00000000..72d1aac6 --- /dev/null +++ b/packages/ui/certd-client/src/router/index.ts @@ -0,0 +1,68 @@ +import { createRouter, createWebHashHistory } from "vue-router"; +// 进度条 +import NProgress from "nprogress"; +import "nprogress/nprogress.css"; +import { usePageStore } from "../store/modules/page"; +import { site } from "../utils/util.site"; +import { routes } from "./resolve"; +import { useResourceStore } from "../store/modules/resource"; +import { useUserStore } from "../store/modules/user"; +const router = createRouter({ + history: createWebHashHistory(), + routes +}); + +/** + * 路由拦截 + */ +router.beforeEach(async (to, from, next) => { + // 进度条 + NProgress.start(); + + // 验证当前路由所有的匹配中是否需要有登录验证的 + if ( + to.matched.some((r) => { + return r.meta?.auth || r.meta?.permission; + }) + ) { + const userStore = useUserStore(); + // 这里暂时将cookie里是否存有token作为验证是否登录的条件 + // 请根据自身业务需要修改 + const token = userStore.getToken; + if (token) { + next(); + } else { + // 没有登录的时候跳转到登录界面 + // 携带上登陆成功之后需要跳转的页面完整路径 + next({ + name: "login", + query: { + redirect: to.fullPath + } + }); + // https://github.com/d2-projects/d2-admin/issues/138 + NProgress.done(); + } + } else { + // 不需要身份校验 直接通过 + next(); + } +}); + +router.afterEach((to) => { + // 进度条 + NProgress.done(); + // 多页控制 打开新的页面 + const pageStore = usePageStore(); + pageStore.open(to); + // 更改标题 + site.title(to.meta.title); + + //修改左侧边栏 + const matched = to.matched; + if (matched.length > 0) { + const resourceStore = useResourceStore(); + resourceStore.setAsideMenuByCurrentRoute(matched); + } +}); +export default router; diff --git a/packages/ui/certd-client/src/router/resolve.ts b/packages/ui/certd-client/src/router/resolve.ts new file mode 100644 index 00000000..39cbd998 --- /dev/null +++ b/packages/ui/certd-client/src/router/resolve.ts @@ -0,0 +1,155 @@ +import LayoutPass from "/src/layout/layout-pass.vue"; +import _ from "lodash-es"; +import { outsideResource } from "./source/outside"; +import { headerResource } from "./source/header"; +import { frameworkResource } from "./source/framework"; +// @ts-ignore +const modules = import.meta.glob("/src/views/**/*.vue"); + +let index = 0; +function transformOneResource(resource) { + let menu: any = null; + if (resource.meta == null) { + resource.meta = {}; + } + const meta = resource.meta; + meta.title = meta.title ?? resource.title ?? "未命名"; + if (resource.title == null) { + resource.title = meta.title; + } + if (meta.isMenu === false) { + menu = null; + } else { + menu = _.cloneDeep(resource); + delete menu.component; + } + let route; + if (resource.type !== "menu") { + if (resource.path == null || resource.path.startsWith("https://") || resource.path.startsWith("http://")) { + //没有route + route = null; + } else { + route = _.cloneDeep(resource); + if (route.component && typeof route.component === "string") { + const path = "/src/views" + route.component; + route.component = modules[path]; + } + if (route.component == null) { + route.component = LayoutPass; + } + } + } + + return { + menu, + route + }; +} + +export const buildMenusAndRouters = (resources) => { + const routes: Array = []; + const menus: Array = []; + for (const item of resources) { + const { menu, route } = transformOneResource(item); + let menuChildren; + let routeChildren; + if (item.children) { + if (item.children.length > 0) { + const ret = buildMenusAndRouters(item.children); + menuChildren = ret.menus; + routeChildren = ret.routes; + } + } + + if (menu) { + menus.push(menu); + menu.children = menuChildren; + } + if (route) { + if (route?.meta?.cache !== false) { + if (route.meta == null) { + route.meta = {}; + } + route.meta.cache = true; + } + routes.push(route); + route.children = routeChildren; + } + } + + setIndex(menus); + return { + routes, + menus + }; +}; + +function setIndex(menus) { + for (const menu of menus) { + menu.index = "index_" + index; + index++; + if (menu.children && menu.children.length > 0) { + setIndex(menu.children); + } + } +} + +function findMenus(menus, condition) { + const list: any = []; + for (const menu of menus) { + if (condition(menu)) { + list.push(menu); + } + if (menu.children && menu.children.length > 0) { + const subList = findMenus(menu.children, condition); + for (const item of subList) { + list.push(item); + } + } + } + return list; +} + +function filterMenus(menus, condition) { + const list = menus.filter((item) => { + return condition(item); + }); + + for (const item of list) { + if (item.children && item.children.length > 0) { + item.children = filterMenus(item.children, condition); + } + } + return list; +} + +function flatChildren(list, children) { + for (const child of children) { + list.push(child); + if (child.children && child.children.length > 0) { + flatChildren(list, child.children); + } + child.children = null; + } +} +function flatSubRouters(routers) { + for (const router of routers) { + const children: Array = []; + if (router.children && router.children.length > 0) { + flatChildren(children, router.children); + } + router.children = children; + } + return routers; +} + +const frameworkRet = buildMenusAndRouters(frameworkResource); +const outsideRet = buildMenusAndRouters(outsideResource); +const headerRet = buildMenusAndRouters(headerResource); + +const outsideRoutes = outsideRet.routes; +const frameworkRoutes = flatSubRouters(frameworkRet.routes); +const routes = [...outsideRoutes, ...frameworkRoutes]; +const frameworkMenus = frameworkRet.menus; +const headerMenus = headerRet.menus; +export { routes, outsideRoutes, frameworkRoutes, frameworkMenus, headerMenus, findMenus, filterMenus }; diff --git a/packages/ui/certd-client/src/router/source/framework.ts b/packages/ui/certd-client/src/router/source/framework.ts new file mode 100644 index 00000000..45366ca2 --- /dev/null +++ b/packages/ui/certd-client/src/router/source/framework.ts @@ -0,0 +1,31 @@ +import LayoutFramework from "/src/layout/layout-framework.vue"; +import { crudResources } from "/@/router/source/modules/crud"; +import { sysResources } from "/@/router/source/modules/sys"; +export const frameworkResource = [ + { + title: "框架", + name: "framework", + path: "/", + redirect: "/index", + component: LayoutFramework, + meta: { + icon: "ion:accessibility" + }, + children: [ + { + title: "首页", + name: "index", + path: "/index", + component: "/framework/home/index.vue", + meta: { + fixedAside: true, + showOnHeader: false, + icon: "ion:home-outline" + } + }, + ...crudResources, + ...sysResources + ] + } +]; +console.assert(frameworkResource.length === 1, "frameworkResource数组长度只能为1,你只能配置framework路由的子路由"); diff --git a/packages/ui/certd-client/src/router/source/header.ts b/packages/ui/certd-client/src/router/source/header.ts new file mode 100644 index 00000000..8c30304a --- /dev/null +++ b/packages/ui/certd-client/src/router/source/header.ts @@ -0,0 +1,73 @@ +export const headerResource = [ + { + title: "文档", + path: "http://fast-crud.docmirror.cn/" + }, + { + title: "其他Demo", + name: "demo", + children: [ + { + title: "Element版", + path: "http://fast-crud.docmirror.cn/element/" + }, + { + title: "VbenAdmin", + path: "http://fast-crud.docmirror.cn/vben/" + }, + { + title: "cool-admin-vue", + path: "http://fast-crud.docmirror.cn/cool/" + } + ] + }, + + { + title: "源码", + name: "source", + key: "source", + meta: { + icon: "ion:git-branch-outline" + }, + children: [ + { + title: "fast-crud", + children: [ + { + title: "github", + path: "http://github.com/fast-crud/fast-crud", + meta: { + icon: "ion:logo-github" + } + }, + { + title: "gitee", + path: "http://gitee.com/fast-crud/fast-crud", + meta: { + icon: "ion:logo-octocat" + } + } + ] + }, + { + title: "fs-admin", + children: [ + { + title: "github", + path: "http://github.com/fast-crud/fs-admin-antdv", + meta: { + icon: "ion:logo-github" + } + }, + { + title: "gitee", + path: "http://gitee.com/fast-crud/fs-admin-antdv", + meta: { + icon: "ion:logo-octocat" + } + } + ] + } + ] + } +]; diff --git a/packages/ui/certd-client/src/router/source/modules/crud.ts b/packages/ui/certd-client/src/router/source/modules/crud.ts new file mode 100644 index 00000000..226ff916 --- /dev/null +++ b/packages/ui/certd-client/src/router/source/modules/crud.ts @@ -0,0 +1,635 @@ +export const crudResources = [ + { + title: "CRUD示例", + name: "crud", + path: "/crud", + redirect: "/crud/basis", + meta: { + icon: "ion:apps-sharp" + }, + children: [ + { + title: "基本特性", + name: "basis", + path: "/crud/basis", + redirect: "/crud/basis/i18n", + meta: { + icon: "ion:disc-outline" + }, + children: [ + { + title: "HelloWorld", + name: "FsCrudFirst", + path: "/crud/basis/first", + component: "/crud/basis/first/index.vue" + }, + { + title: "动态计算", + name: "BasisCompute", + path: "/crud/basis/compute", + component: "/crud/basis/compute/index.vue" + }, + { + title: "动态计算-更多示例", + name: "BasisComputeMore", + path: "/crud/basis/compute-more", + component: "/crud/basis/compute-more/index.vue" + }, + { + title: "国际化", + name: "BasisI18n", + path: "/crud/basis/i18n", + component: "/crud/basis/i18n/index.vue" + }, + { + title: "ValueChange", + name: "BasisValueChange", + path: "/crud/basis/value-change", + component: "/crud/basis/value-change/index.vue" + }, + { + title: "Card布局", + name: "BasisLayoutCard", + path: "/crud/basis/layout-card", + component: "/crud/basis/layout-card/index.vue" + }, + { + title: "自定义布局", + name: "BasisLayoutCustom", + path: "/crud/basis/layout-custom", + component: "/crud/basis/layout-custom/index.vue" + }, + { + title: "列设置", + name: "BasisColumnsSet", + path: "/crud/basis/columns-set", + component: "/crud/basis/columns-set/index.vue" + }, + { + title: "字段合并插件", + name: "BasisColumnMergePlugin", + path: "/crud/basis/column-merge-plugin", + component: "/crud/basis/column-merge-plugin/index.vue" + } + ] + }, + { + title: "数据字典", + name: "dict", + path: "/crud/dict", + redirect: "/crud/dict/single", + meta: { + icon: "ion:book-outline" + }, + children: [ + { + title: "单例", + name: "DictSingle", + path: "/crud/dict/single", + component: "/crud/dict/single/index.vue" + }, + { + title: "分发复制", + name: "DictCloneable", + path: "/crud/dict/cloneable", + component: "/crud/dict/cloneable/index.vue" + }, + { + title: "原型复制", + name: "DictPrototype", + path: "/crud/dict/prototype", + component: "/crud/dict/prototype/index.vue" + }, + { + title: "页面间共享", + name: "DictShared", + path: "/crud/dict/shared", + children: [ + { + title: "共享字典数据管理", + name: "DictSharedManager", + path: "/crud/dict/shared/manager", + component: "/crud/dict/shared/manager/index.vue" + }, + { + title: "共享字典使用", + name: "DictSharedUse", + path: "/crud/dict/shared/use", + component: "/crud/dict/shared/use/index.vue" + } + ] + } + ] + }, + { + title: "操作列", + name: "row-handle", + path: "/crud/row-handle", + redirect: "/crud/row-handle/tooltip", + meta: { + icon: "ion:build-outline" + }, + children: [ + { + title: "Tooltip", + name: "RowHandleTooltip", + path: "/crud/row-handle/tooltip", + component: "/crud/row-handle/tooltip/index.vue" + }, + { + title: "按钮折叠", + name: "RowHandleDropdown", + path: "/crud/row-handle/dropdown", + component: "/crud/row-handle/dropdown/index.vue" + } + ] + }, + { + title: "组件示例", + name: "component", + path: "/crud/component", + redirect: "/crud/component/text", + meta: { + icon: "ion:cube-outline" + }, + children: [ + { + title: "文本输入(input)", + name: "ComponentText", + path: "/crud/component/text", + component: "/crud/component/text/index.vue" + }, + { + title: "选择(select)", + name: "ComponentSelect", + path: "/crud/component/select", + component: "/crud/component/select/index.vue" + }, + { + title: "级联(cascader)", + name: "ComponentCascader", + path: "/crud/component/cascader", + component: "/crud/component/cascader/index.vue" + }, + { + title: "多选(checkbox)", + name: "ComponentCheckbox", + path: "/crud/component/checkbox", + component: "/crud/component/checkbox/index.vue" + }, + { + title: "单选(radio)", + name: "ComponentRadio", + path: "/crud/component/radio", + component: "/crud/component/radio/index.vue" + }, + { + title: "开关(switch)", + name: "ComponentSwitch", + path: "/crud/component/switch", + component: "/crud/component/switch/index.vue" + }, + { + title: "日期时间(date)", + name: "ComponentDate", + path: "/crud/component/date", + component: "/crud/component/date/index.vue" + }, + { + title: "按钮链接", + name: "ComponentButton", + path: "/crud/component/button", + component: "/crud/component/button/index.vue" + }, + { + title: "数字", + name: "ComponentNumber", + path: "/crud/component/number", + component: "/crud/component/number/index.vue" + }, + { + title: "树形选择", + name: "ComponentTree", + path: "/crud/component/tree", + component: "/crud/component/tree/index.vue" + }, + { + title: "图片裁剪上传", + name: "ComponentUploaderCropper", + path: "/crud/component/uploader/cropper", + component: "/crud/component/uploader/cropper/index.vue" + }, + { + title: "表单本地上传", + name: "ComponentUploaderForm", + path: "/crud/component/uploader/form", + component: "/crud/component/uploader/form/index.vue" + }, + { + title: "阿里云oss上传", + name: "ComponentUploaderAlioss", + path: "/crud/component/uploader/alioss", + component: "/crud/component/uploader/alioss/index.vue" + }, + { + title: "腾讯云cos上传", + name: "ComponentUploaderCos", + path: "/crud/component/uploader/cos", + component: "/crud/component/uploader/cos/index.vue" + }, + { + title: "七牛云上传", + name: "ComponentUploaderQiniu", + path: "/crud/component/uploader/qiniu", + component: "/crud/component/uploader/qiniu/index.vue" + }, + { + title: "富文本编辑器", + name: "ComponentEditor", + path: "/crud/component/editor", + component: "/crud/component/editor/index.vue" + }, + { + title: "图标", + name: "ComponentIcon", + path: "/crud/component/icon", + component: "/crud/component/icon/index.vue" + }, + { + title: "JsonEditor", + name: "ComponentJson", + path: "/crud/component/json", + component: "/crud/component/json/index.vue" + } + ] + }, + { + title: "Form表单", + name: "form", + path: "/crud/form", + redirect: "/crud/form/layout", + meta: { + icon: "ion:document-text-outline" + }, + children: [ + { + title: "基本表单", + name: "FormBase", + path: "/crud/form/base", + component: "/crud/form/base/index.vue" + }, + { + title: "表单Grid布局", + name: "FormLayoutGrid", + path: "/crud/form/layout-grid", + component: "/crud/form/layout-grid/index.vue" + }, + { + title: "表单Flex布局", + name: "FormLayoutFlex", + path: "/crud/form/layout-flex", + component: "/crud/form/layout-flex/index.vue" + }, + { + title: "表单动态布局", + name: "FormLayout", + path: "/crud/form/layout", + component: "/crud/form/layout/index.vue" + }, + { + title: "表单单列模式", + name: "FormSingleColumn", + path: "/crud/form/single-column", + component: "/crud/form/single-column/index.vue" + }, + { + title: "表单校验", + name: "FormValidation", + path: "/crud/form/validation", + component: "/crud/form/validation/index.vue" + }, + { + title: "抽屉表单", + name: "FormDrawer", + path: "/crud/form/drawer", + component: "/crud/form/drawer/index.vue" + }, + { + title: "表单分组", + name: "FormGroup", + path: "/crud/form/group", + component: "/crud/form/group/index.vue" + }, + { + title: "表单分组(tabs)", + name: "FormGroupTabs", + path: "/crud/form/group-tabs", + component: "/crud/form/group-tabs/index.vue" + }, + { + title: "自定义表单", + name: "FormCustomForm", + path: "/crud/form/custom-form", + component: "/crud/form/custom-form/index.vue" + }, + { + title: "字段帮助说明", + name: "FormHelper", + path: "/crud/form/helper", + component: "/crud/form/helper/index.vue" + }, + { + title: "页面内部弹出表单", + name: "FormInner", + path: "/crud/form/inner", + component: "/crud/form/inner/index.vue", + meta: { + cache: true + } + }, + { + title: "地区字典管理", + name: "FormInnerArea", + path: "/crud/form/inner/area", + component: "/crud/form/inner/area/index.vue", + meta: { + isMenu: false + } + }, + { + title: "新页面编辑", + name: "FormNewPage", + path: "/crud/form/new-page", + component: "/crud/form/new-page/index.vue", + meta: { + cache: false + } + }, + { + title: "新页面编辑表单", + name: "FormNewPageEdit", + path: "/crud/form/new-page/edit", + component: "/crud/form/new-page/edit.vue", + meta: { + isMenu: false + } + }, + { + title: "独立使用表单", + name: "FormIndependent", + path: "/crud/form/independent", + component: "/crud/form/independent/index.vue" + }, + { + title: "重置表单", + name: "FormReset", + path: "/crud/form/reset", + component: "/crud/form/reset/index.vue" + }, + { + title: "嵌套数据结构", + name: "FormNest", + path: "/crud/form/nest", + component: "/crud/form/nest/index.vue" + } + ] + }, + { + title: "表格特性", + path: "/crud/feature", + meta: { + icon: "ion:beer-outline" + }, + redirect: "/crud/feature/dropdown", + children: [ + { + title: "部件显隐", + name: "FeatureHide", + path: "/crud/feature/hide", + component: "/crud/feature/hide/index.vue" + }, + { + title: "多选&批量删除", + name: "FeatureSelection", + path: "/crud/feature/selection", + component: "/crud/feature/selection/index.vue" + }, + { + title: "单选", + name: "FeatureSelectionRadio", + path: "/crud/feature/selection-radio", + component: "/crud/feature/selection-radio/index.vue" + }, + { + title: "表头过滤", + name: "FeatureFilter", + path: "/crud/feature/filter", + component: "/crud/feature/filter/index.vue" + }, + { + title: "行展开", + name: "FeatureExpand", + path: "/crud/feature/expand", + component: "/crud/feature/expand/index.vue" + }, + { + title: "树形表格", + name: "FeatureTree", + path: "/crud/feature/tree", + component: "/crud/feature/tree/index.vue" + }, + { + title: "多级表头", + name: "FeatureHeaderGroup", + path: "/crud/feature/header-group", + component: "/crud/feature/header-group/index.vue" + }, + { + title: "合并单元格", + name: "FeatureMerge", + path: "/crud/feature/merge", + component: "/crud/feature/merge/index.vue" + }, + { + title: "序号", + name: "FeatureIndex", + path: "/crud/feature/index", + component: "/crud/feature/index/index.vue" + }, + { + title: "排序", + name: "FeatureSortable", + path: "/crud/feature/sortable", + component: "/crud/feature/sortable/index.vue" + }, + { + title: "固定列", + name: "FeatureFixed", + path: "/crud/feature/fixed", + component: "/crud/feature/fixed/index.vue" + }, + { + title: "不固定高度", + name: "FeatureHeight", + path: "/crud/feature/height", + component: "/crud/feature/height/index.vue" + }, + { + title: "可编辑", + name: "FeatureEditable", + path: "/crud/feature/editable", + component: "/crud/feature/editable/index.vue" + }, + { + title: "行编辑", + name: "FeatureEditableRow", + path: "/crud/feature/editable-row", + component: "/crud/feature/editable-row/index.vue" + }, + { + title: "查询框", + name: "FeatureSearch", + path: "/crud/feature/search", + component: "/crud/feature/search/index.vue" + }, + { + title: "查询框多行模式", + name: "FeatureSearchMulti", + path: "/crud/feature/search-multi", + component: "/crud/feature/search-multi/index.vue" + }, + { + title: "字段排序", + name: "FeatureColumnSort", + path: "/crud/feature/column-sort", + component: "/crud/feature/column-sort/index.vue" + }, + { + title: "ValueBuilder", + name: "FeatureValueBuilder", + path: "/crud/feature/value-builder", + component: "/crud/feature/value-builder/index.vue" + }, + { + title: "列设置", + name: "FeatureColumnsSet", + path: "/crud/feature/columns-set", + component: "/crud/feature/columns-set/index.vue" + }, + { + title: "本地化编辑", + name: "FeatureLocal", + path: "/crud/feature/local", + component: "/crud/feature/local/index.vue" + }, + { + title: "v-model", + name: "FeatureVModel", + path: "/crud/feature/v-model", + component: "/crud/feature/local-v-model/index.vue" + }, + { + title: "自定义删除", + name: "FeatureRemove", + path: "/crud/feature/remove", + component: "/crud/feature/remove/index.vue" + }, + { + title: "调整列宽", + name: "FeatureColumnResize", + path: "/crud/feature/column-resize", + component: "/crud/feature/column-resize/index.vue" + } + ] + }, + { + title: "插槽", + name: "Slots", + path: "/crud/slots", + redirect: "/crud/slots/layout", + meta: { + icon: "ion:extension-puzzle-outline" + }, + children: [ + { + title: "页面占位插槽", + name: "SlotsLayout", + path: "/crud/slots/layout", + component: "/crud/slots/layout/index.vue" + }, + { + title: "表单占位插槽", + name: "SlotsForm", + path: "/crud/slots/form", + component: "/crud/slots/form/index.vue" + }, + { + title: "查询字段插槽", + name: "SlotsSearch", + path: "/crud/slots/search", + component: "/crud/slots/search/index.vue" + }, + { + title: "单元格插槽", + name: "SlotsCell", + path: "/crud/slots/cell", + component: "/crud/slots/cell/index.vue" + }, + { + title: "表单字段插槽", + name: "SlotsFormItem", + path: "/crud/slots/form-item", + component: "/crud/slots/form-item/index.vue" + } + ] + }, + { + title: "复杂需求", + name: "Advanced", + path: "/crud/advanced", + redirect: "/crud/advanced/linkage", + meta: { + icon: "ion:flame-outline" + }, + children: [ + { + title: "选择联动", + name: "AdvancedLinkage", + path: "/crud/advanced/linkage", + component: "/crud/advanced/linkage/index.vue" + }, + { + title: "后台加载crud", + name: "AdvancedFormBackend", + path: "/crud/advanced/from-backend", + component: "/crud/advanced/from-backend/index.vue" + }, + { + title: "本地分页", + name: "AdvancedLocalPagination", + path: "/crud/advanced/local-pagination", + component: "/crud/advanced/local-pagination/index.vue" + }, + { + title: "嵌套子表格", + name: "AdvancedNest", + path: "/crud/advanced/nest", + component: "/crud/advanced/nest/index.vue" + }, + { + title: "对话框中显示crud", + name: "AdvancedInDialog", + path: "/crud/advanced/in-dialog", + component: "/crud/advanced/in-dialog/index.vue" + }, + { + title: "大量数据", + name: "AdvancedBigData", + path: "/crud/advanced/big-data", + component: "/crud/advanced/big-data/index.vue" + } + ] + } + ] + } +]; diff --git a/packages/ui/certd-client/src/router/source/modules/sys.ts b/packages/ui/certd-client/src/router/source/modules/sys.ts new file mode 100644 index 00000000..a2d75127 --- /dev/null +++ b/packages/ui/certd-client/src/router/source/modules/sys.ts @@ -0,0 +1,61 @@ +import LayoutPass from "/@/layout/layout-pass.vue"; + +export const sysResources = [ + { + title: "系统管理", + name: "sys", + path: "/sys", + redirect: "/sys/authority", + component: LayoutPass, + meta: { + icon: "ion:settings-outline", + permission: "sys" + }, + children: [ + { + title: "权限管理", + name: "authority", + path: "/sys/authority", + redirect: "/sys/authority/permission", + meta: { + icon: "ion:ribbon-outline", + //需要校验权限 + permission: "sys:auth" + }, + children: [ + { + title: "权限资源管理", + name: "permission", + meta: { + icon: "ion:list-outline", + //需要校验权限 + permission: "sys:auth:per:view" + }, + path: "/sys/authority/permission", + component: "/sys/authority/permission/index.vue" + }, + { + title: "角色管理", + name: "role", + meta: { + icon: "ion:people-outline", + permission: "sys:auth:role:view" + }, + path: "/sys/authority/role", + component: "/sys/authority/role/index.vue" + } + ] + }, + { + title: "用户管理", + name: "user", + meta: { + icon: "ion:person-outline", + permission: "sys:auth:user:view" + }, + path: "/sys/authority/user", + component: "/sys/authority/user/index.vue" + } + ] + } +]; diff --git a/packages/ui/certd-client/src/router/source/outside.ts b/packages/ui/certd-client/src/router/source/outside.ts new file mode 100644 index 00000000..177172c3 --- /dev/null +++ b/packages/ui/certd-client/src/router/source/outside.ts @@ -0,0 +1,22 @@ +import LayoutOutside from "/src/layout/layout-outside.vue"; +import Error404 from "/src/views/framework/error/404.vue"; +const errorPage = [{ path: "/:pathMatch(.*)*", name: "not-found", component: Error404 }]; +export const outsideResource = [ + { + title: "outside", + name: "outside", + path: "/outside", + component: LayoutOutside, + children: [ + { + meta: { + title: "登录" + }, + name: "login", + path: "/login", + component: "/framework/login/index.vue" + } + ] + }, + ...errorPage +]; diff --git a/packages/ui/certd-client/src/shims-vue.d.ts b/packages/ui/certd-client/src/shims-vue.d.ts new file mode 100644 index 00000000..daba9b9e --- /dev/null +++ b/packages/ui/certd-client/src/shims-vue.d.ts @@ -0,0 +1,5 @@ +declare module "*.vue" { + import { DefineComponent } from "vue"; + const component: DefineComponent<{}, {}, any>; + export default component; +} diff --git a/packages/ui/certd-client/src/store/index.ts b/packages/ui/certd-client/src/store/index.ts new file mode 100644 index 00000000..52b9cf68 --- /dev/null +++ b/packages/ui/certd-client/src/store/index.ts @@ -0,0 +1,9 @@ +import { createPinia } from "pinia"; +const store = createPinia(); +export default { + install(app) { + app.use(store); + } +}; + +export { store }; diff --git a/packages/ui/certd-client/src/store/modules/page.ts b/packages/ui/certd-client/src/store/modules/page.ts new file mode 100644 index 00000000..8c2d7176 --- /dev/null +++ b/packages/ui/certd-client/src/store/modules/page.ts @@ -0,0 +1,436 @@ +import { defineStore } from "pinia"; +import { cloneDeep, get, uniq } from "lodash-es"; +import router from "/src/router"; +import { frameworkRoutes } from "/src/router/resolve"; +// @ts-ignore +import { LocalStorage } from "/src/utils/util.storage"; +import { useUserStore } from "/src/store/modules/user"; +const OPENED_CACHE_KEY = "TABS_OPENED"; + +interface PageState { + // 可以在多页 tab 模式下显示的页面 + pool: Array; + // 当前显示的多页面列表 + opened: Array; + // 已经加载多标签页数据 https://github.com/d2-projects/d2-admin/issues/201 + openedLoaded: boolean; + // 当前页面 + current: ""; + // 需要缓存的页面 name + keepAlive: Array; + inited: boolean; +} +// 判定是否需要缓存 +const isKeepAlive = (data) => get(data, "meta.cache", false); + +export const usePageStore = defineStore({ + id: "app.page", + state: (): PageState => ({ + // 可以在多页 tab 模式下显示的页面 + pool: [], + // 当前显示的多页面列表 + opened: [ + { + name: "index", + fullPath: "/index", + meta: { + title: "首页", + auth: false + } + } + ], + // 已经加载多标签页数据 https://github.com/d2-projects/d2-admin/issues/201 + openedLoaded: false, + // 当前页面 + current: "", + // 需要缓存的页面 name + keepAlive: [], + inited: false + }), + getters: { + getOpened() { + // @ts-ignore + return this.opened; + }, + getCurrent(): string { + return this.current; + } + }, + actions: { + /** + * @description 确认已经加载多标签页数据 https://github.com/d2-projects/d2-admin/issues/201 + * @param {Object} context + */ + async isLoaded() { + if (this.openedLoaded) { + return true; + } + return new Promise((resolve) => { + const timer = setInterval(() => { + if (this.openedLoaded) { + resolve(clearInterval(timer)); + } + }, 10); + }); + }, + /** + * @class opened + * @description 从持久化数据载入标签页列表 + * @param {Object} context + */ + async openedLoad() { + // store 赋值 + const value = LocalStorage.get(this.getStorageKey()); + if (value == null) { + return; + } + // 在处理函数中进行数据优化 过滤掉现在已经失效的页签或者已经改变了信息的页签 + // 以 fullPath 字段为准 + // 如果页面过多的话可能需要优化算法 + // valid 有效列表 1, 1, 0, 1 => 有效, 有效, 失效, 有效 + const valid: Array = []; + // 处理数据 + this.opened = value + .map((opened) => { + // 忽略首页 + if (opened.fullPath === "/index") { + valid.push(1); + return opened; + } + // 尝试在所有的支持多标签页的页面里找到 name 匹配的页面 + const find = this.pool.find((item) => item.name === opened.name); + // 记录有效或无效信息 + valid.push(find ? 1 : 0); + // 返回合并后的数据 新的覆盖旧的 + // 新的数据中一般不会携带 params 和 query, 所以旧的参数会留存 + return Object.assign({}, opened, find); + }) + .filter((opened, index) => valid[index] === 1); + // 标记已经加载多标签页数据 https://github.com/d2-projects/d2-admin/issues/201 + this.openedLoaded = true; + // 根据 opened 数据生成缓存设置 + this.keepAliveRefresh(); + }, + + getStorageKey() { + const userStore = useUserStore(); + const userId = userStore.getUserInfo?.id ?? "anonymous"; + return OPENED_CACHE_KEY + ":" + userId; + }, + /** + * 将 opened 属性赋值并持久化 在这之前请先确保已经更新了 state.opened + * @param {Object} context + */ + async opened2db() { + // 设置数据 + + LocalStorage.set(this.getStorageKey(), this.opened); + }, + /** + * @class opened + * @description 更新页面列表上的某一项 + * @param {Object} context + * @param {Object} payload { index, params, query, fullPath } 路由信息 + */ + async openedUpdate({ index, params, query, fullPath }) { + // 更新页面列表某一项 + const page = this.opened[index]; + page.params = params || page.params; + page.query = query || page.query; + page.fullPath = fullPath || page.fullPath; + this.opened.splice(index, 1, page); + // 持久化 + await this.opened2db(); + }, + /** + * @class opened + * @description 重排页面列表上的某一项 + * @param {Object} context + * @param {Object} payload { oldIndex, newIndex } 位置信息 + */ + async openedSort({ oldIndex, newIndex }) { + // 重排页面列表某一项 + const page = this.opened[oldIndex]; + this.opened.splice(oldIndex, 1); + this.opened.splice(newIndex, 0, page); + // 持久化 + await this.opened2db(); + }, + /** + * @class opened + * @description 新增一个 tag (打开一个页面) + * @param {Object} context + * @param {Object} payload new tag info + */ + async add({ tag, params, query, fullPath }) { + // 设置新的 tag 在新打开一个以前没打开过的页面时使用 + const newTag = tag; + newTag.params = params || newTag.params; + newTag.query = query || newTag.query; + newTag.fullPath = fullPath || newTag.fullPath; + // 添加进当前显示的页面数组 + this.opened.push(newTag); + // 如果这个页面需要缓存 将其添加到缓存设置 + if (isKeepAlive(newTag)) { + this.keepAlivePush(tag.name); + } + // 持久化 + await this.opened2db(); + }, + /** + * @class current + * @description 打开一个新的页面 + * @param {Object} context + * @param {Object} payload 从路由钩子的 to 对象上获取 { name, params, query, fullPath, meta } 路由信息 + */ + async open({ name, params, query, fullPath, meta }) { + // 已经打开的页面 + const opened = this.opened; + // 判断此页面是否已经打开 并且记录位置 + let pageOpendIndex = 0; + const pageOpend = opened.find((page, index) => { + const same = page.fullPath === fullPath; + pageOpendIndex = same ? index : pageOpendIndex; + return same; + }); + if (pageOpend) { + // 页面以前打开过 + await this.openedUpdate({ + index: pageOpendIndex, + params, + query, + fullPath + }); + } else { + // 页面以前没有打开过 + const page = this.pool.find((t) => t.name === name); + // 如果这里没有找到 page 代表这个路由虽然在框架内 但是不参与标签页显示 + if (page) { + this.add({ + tag: Object.assign({}, page), + params, + query, + fullPath + }); + } + } + // 如果这个页面需要缓存 将其添加到缓存设置 + if (isKeepAlive({ meta })) { + this.keepAlivePush(name); + } + // 设置当前的页面 + this.currentSet(fullPath); + }, + /** + * @class opened + * @description 关闭一个 tag (关闭一个页面) + * @param {Object} context + * @param {Object} payload { tagName: 要关闭的标签名字 } + */ + async close({ tagName }) { + // 预定下个新页面 + let newPage = {}; + const isCurrent = this.current === tagName; + // 如果关闭的页面就是当前显示的页面 + if (isCurrent) { + // 去找一个新的页面 + const len = this.opened.length; + for (let i = 0; i < len; i++) { + if (this.opened[i].fullPath === tagName) { + newPage = i < len - 1 ? this.opened[i + 1] : this.opened[i - 1]; + break; + } + } + } + // 找到这个页面在已经打开的数据里是第几个 + const index = this.opened.findIndex((page) => page.fullPath === tagName); + if (index >= 0) { + // 如果这个页面是缓存的页面 将其在缓存设置中删除 + this.keepAliveRemove(this.opened[index].name); + // 更新数据 删除关闭的页面 + this.opened.splice(index, 1); + } + // 持久化 + await this.opened2db(); + // 决定最后停留的页面 + if (isCurrent) { + // @ts-ignore + const { name = "index", params = {}, query = {} } = newPage; + const routerObj = { name, params, query }; + await router.push(routerObj); + } + }, + /** + * @class opened + * @description 关闭当前标签左边的标签 + * @param opts + */ + async closeLeft(opts = {}) { + await this.closeByCondition({ + condition({ i, currentIndex }) { + return i >= currentIndex; + }, + ...opts + }); + }, + /** + * @class opened + * @description 关闭当前标签右边的标签 + * @param opts + */ + async closeRight(opts = {}) { + await this.closeByCondition({ + condition({ i, currentIndex }) { + return currentIndex >= i; + }, + ...opts + }); + }, + /** + * @class opened + * @description 关闭当前标签右边的标签 + * @param opts + */ + async closeByCondition(opts = {}) { + // @ts-ignore + const { pageSelect, condition } = opts; + const pageAim = pageSelect || this.current; + let currentIndex = 0; + this.opened.forEach((page, index) => { + if (page.fullPath === pageAim) currentIndex = index; + }); + // 删除打开的页面 并在缓存设置中删除 + for (let i = this.opened.length - 1; i >= 0; i--) { + if (this.opened[i].name === "index" || condition({ i, currentIndex })) { + continue; + } + this.keepAliveRemove(this.opened[i].name); + this.opened.splice(i, 1); + } + // 持久化 + await this.opened2db(); + // 设置当前的页面 + this.current = pageAim; + // @ts-ignore + if (router.currentRoute.fullPath !== pageAim) await router.push(pageAim); + }, + /** + * @class opened + * @description 关闭当前激活之外的 tag + * @param opts + */ + async closeOther(opts = {}) { + await this.closeByCondition({ + condition({ i, currentIndex }) { + return currentIndex === i; + }, + ...opts + }); + }, + /** + * @class opened + * @description 关闭所有 tag + * @param {Object} context + */ + async closeAll() { + // 删除打开的页面 并在缓存设置中删除 + for (let i = this.opened.length - 1; i >= 0; i--) { + if (this.opened[i].name === "index") { + continue; + } + + this.keepAliveRemove(this.opened[i].name); + this.opened.splice(i, 1); + } + // 持久化 + await this.opened2db(); + // 关闭所有的标签页后需要判断一次现在是不是在首页 + // @ts-ignore + if (router.currentRoute.name !== "index") { + await router.push({ name: "index" }); + } + }, + /** + * @class keepAlive + * @description 从已经打开的页面记录中更新需要缓存的页面记录 + * @param {Object} state state + */ + keepAliveRefresh() { + this.keepAlive = this.opened.filter((item) => isKeepAlive(item)).map((e) => e.name); + console.log("keep alive:", this.keepAlive); + }, + /** + * @description 删除一个页面的缓存设置 + * @param {Object} state state + * @param {String} name name + */ + keepAliveRemove(name) { + const list = cloneDeep(this.keepAlive); + const index = list.findIndex((item) => item === name); + if (index !== -1) { + list.splice(index, 1); + this.keepAlive = list; + } + }, + /** + * @description 增加一个页面的缓存设置 + * @param {Object} state state + * @param {String} name name + */ + keepAlivePush(name) { + const keep = cloneDeep(this.keepAlive); + keep.push(name); + this.keepAlive = uniq(keep); + }, + /** + * @description 清空页面缓存设置 + * @param {Object} state state + */ + keepAliveClean() { + this.keepAlive = []; + }, + /** + * @class current + * @description 设置当前激活的页面 fullPath + * @param {Object} state state + * @param {String} fullPath new fullPath + */ + currentSet(fullPath) { + this.current = fullPath; + }, + /** + * @class pool + * @description 保存 pool (候选池) + * @param {Object} state state + * @param {Array} routes routes + */ + async init(routes) { + if (this.inited) { + return; + } + this.inited = true; + if (routes == null) { + //不能用全部的routes,只能是framework内的 + routes = frameworkRoutes; + } + + const pool = []; + const push = function (routes) { + routes.forEach((route) => { + if (route.children && route.children.length > 0) { + push(route.children); + } else { + if (!route.hidden) { + const { meta, name, path } = route; + // @ts-ignore + pool.push({ meta, name, path }); + } + } + }); + }; + push(routes); + this.pool = pool; + await this.openedLoad(); + } + } +}); diff --git a/packages/ui/certd-client/src/store/modules/resource.ts b/packages/ui/certd-client/src/store/modules/resource.ts new file mode 100644 index 00000000..33674c97 --- /dev/null +++ b/packages/ui/certd-client/src/store/modules/resource.ts @@ -0,0 +1,127 @@ +import { defineStore } from "pinia"; +// @ts-ignore +import { frameworkMenus, headerMenus, filterMenus, findMenus } from "/src/router/resolve"; +import _ from "lodash-es"; +import { mitter } from "/src/utils/util.mitt"; +//监听注销事件 +mitter.on("app.logout", () => { + const resourceStore = useResourceStore(); + resourceStore.clear(); +}); + +interface ResourceState { + frameworkMenus: Array; + headerMenus: Array; + asideMenus: Array; + fixedAsideMenus: Array; + inited: boolean; + currentAsidePath: string; +} + +export const useResourceStore = defineStore({ + id: "app.resource", + state: (): ResourceState => ({ + // user info + frameworkMenus: [], + headerMenus: [], + asideMenus: [], + fixedAsideMenus: [], + inited: false, + currentAsidePath: "" + }), + getters: { + getAsideMenus() { + return this.asideMenus; + }, + getHeaderMenus() { + return this.headerMenus; + }, + getFrameworkMenus() { + return this.frameworkMenus; + } + }, + actions: { + clear() { + this.inited = false; + }, + /** + * 初始化资源 + */ + init() { + if (this.inited) { + return; + } + this.inited = true; + + const showMenus = _.cloneDeep(frameworkMenus[0].children); + this.frameworkMenus = filterMenus(showMenus, (item) => { + return item?.meta?.showOnHeader !== false; + }); + + this.fixedAsideMenus = findMenus(showMenus, (item) => { + return item?.meta?.fixedAside === true; + }); + this.headerMenus = headerMenus; + this.setAsideMenu(); + }, + setAsideMenu(topMenu?) { + if (this.frameworkMenus.length === 0) { + return; + } + if (topMenu == null) { + topMenu = this.frameworkMenus[0]; + } + const asideMenus = topMenu?.children || []; + this.asideMenus = [...this.fixedAsideMenus, ...asideMenus]; + }, + setAsideMenuByCurrentRoute(matched) { + const menuHeader = this.frameworkMenus; + if (matched?.length <= 1) { + return; + } + + function findFromTree(tree, find) { + const results: Array = []; + for (const item of tree) { + if (find(item)) { + results.push(item); + return results; + } + if (item.children && item.children.length > 0) { + const found = findFromTree(item.children, find); + if (found) { + results.push(item); + return results.concat(found); + } + } + } + } + const matchedPath = matched[1].path; + const _side = findFromTree(menuHeader, (menu) => menu.path === matchedPath); + if (_side?.length > 0) { + if (this.currentAsidePath === _side[0]) { + return; + } + this.currentAsidePath = _side[0]; + this.setAsideMenu(_side[0]); + } + }, + filterByPermission(permissions) { + this.frameworkMenus = this.filterChildrenByPermission(this.frameworkMenus, permissions); + }, + filterChildrenByPermission(list, permissions) { + const menus = list.filter((item) => { + if (item?.meta?.permission) { + return permissions.includes(item.meta.permission); + } + return true; + }); + for (const menu of menus) { + if (menu.children && menu.children.length > 0) { + menu.children = this.filterChildrenByPermission(menu.children, permissions); + } + } + return menus; + } + } +}); diff --git a/packages/ui/certd-client/src/store/modules/settings.ts b/packages/ui/certd-client/src/store/modules/settings.ts new file mode 100644 index 00000000..c5fc0446 --- /dev/null +++ b/packages/ui/certd-client/src/store/modules/settings.ts @@ -0,0 +1,63 @@ +import { defineStore } from "pinia"; +// @ts-ignore +import { LocalStorage } from "/src/utils/util.storage"; +// import { replaceStyleVariables } from "vite-plugin-theme/es/client"; + +// import { getThemeColors, generateColors } from "/src/../build/theme-colors"; +// +// import { mixLighten, mixDarken, tinycolor } from "vite-plugin-theme/es/colorUtils"; + +// export async function changeTheme(color?: string) { +// if (color == null) { +// return; +// } +// const colors = generateColors({ +// mixDarken, +// mixLighten, +// tinycolor, +// color +// }); +// +// return await replaceStyleVariables({ +// colorVariables: [...getThemeColors(color), ...colors] +// }); +// } + +interface SettingState { + theme: any; +} + +const SETTING_THEME_KEY = "SETTING_THEME"; +export const useSettingStore = defineStore({ + id: "app.setting", + state: (): SettingState => ({ + // user info + theme: null + }), + getters: { + getTheme(): any { + return this.theme || LocalStorage.get(SETTING_THEME_KEY) || {}; + } + }, + actions: { + persistTheme() { + LocalStorage.set(SETTING_THEME_KEY, this.getTheme); + }, + async setTheme(theme?: Object) { + if (theme == null) { + theme = this.getTheme; + } + this.theme = theme; + this.persistTheme(); + // await changeTheme(this.theme.primaryColor); + }, + async setPrimaryColor(color) { + const theme = this.theme; + theme.primaryColor = color; + await this.setTheme(); + }, + async init() { + await this.setTheme(this.getTheme); + } + } +}); diff --git a/packages/ui/certd-client/src/store/modules/user.ts b/packages/ui/certd-client/src/store/modules/user.ts new file mode 100644 index 00000000..45ed7b29 --- /dev/null +++ b/packages/ui/certd-client/src/store/modules/user.ts @@ -0,0 +1,106 @@ +import { defineStore } from "pinia"; +import { store } from "../index"; +import router from "../../router"; +// @ts-ignore +import { LocalStorage } from "/src/utils/util.storage"; +// @ts-ignore +import * as UserApi from "/src/api/modules/api.user"; +// @ts-ignore +import { LoginReq, UserInfoRes } from "/@/api/modules/api.user"; +import { Modal } from "ant-design-vue"; +import { useI18n } from "vue-i18n"; + +import { mitter } from "/src/utils/util.mitt"; + +interface UserState { + userInfo: Nullable; + token?: string; +} + +const USER_INFO_KEY = "USER_INFO"; +const TOKEN_KEY = "TOKEN"; +export const useUserStore = defineStore({ + id: "app.user", + state: (): UserState => ({ + // user info + userInfo: null, + // token + token: undefined + }), + getters: { + getUserInfo(): UserInfoRes { + return this.userInfo || LocalStorage.get(USER_INFO_KEY) || {}; + }, + getToken(): string { + return this.token || LocalStorage.get(TOKEN_KEY); + } + }, + actions: { + setToken(info: string, expire: number) { + this.token = info; + LocalStorage.set(TOKEN_KEY, this.token, expire); + }, + setUserInfo(info: UserInfoRes) { + this.userInfo = info; + LocalStorage.set(USER_INFO_KEY, info); + }, + resetState() { + this.userInfo = null; + this.token = ""; + LocalStorage.remove(TOKEN_KEY); + LocalStorage.remove(USER_INFO_KEY); + }, + /** + * @description: login + */ + async login(params: LoginReq): Promise { + try { + const data = await UserApi.login(params); + const { token, expire } = data; + + // save token + this.setToken(token, expire); + // get user info + const userInfo = await this.getUserInfoAction(); + await router.replace("/"); + mitter.emit("app.login", { userInfo, token: data }); + return userInfo; + } catch (error) { + return null; + } + }, + async getUserInfoAction(): Promise { + const userInfo = await UserApi.mine(); + this.setUserInfo(userInfo); + return userInfo; + }, + /** + * @description: logout + */ + logout(goLogin = true) { + this.resetState(); + goLogin && router.push("/login"); + mitter.emit("app.logout"); + }, + + /** + * @description: Confirm before logging out + */ + confirmLoginOut() { + const { t } = useI18n(); + Modal.config({ + iconType: "warning", + title: t("app.login.logoutTip"), + content: t("app.login.logoutMessage"), + onOk: async () => { + await this.logout(true); + } + }); + } + } +}); + +// Need to be used outside the setup +export function useUserStoreWidthOut() { + return useUserStore(store); +} diff --git a/packages/ui/certd-client/src/style.css b/packages/ui/certd-client/src/style.css new file mode 100644 index 00000000..211ee80a --- /dev/null +++ b/packages/ui/certd-client/src/style.css @@ -0,0 +1 @@ +/*占位,勿删*/ diff --git a/packages/ui/certd-client/src/style/common.less b/packages/ui/certd-client/src/style/common.less new file mode 100644 index 00000000..fb8b3b35 --- /dev/null +++ b/packages/ui/certd-client/src/style/common.less @@ -0,0 +1,44 @@ +@import './theme/index.less'; +@import './theme/default.less'; +@import './scroll.less'; +@import './transition.less'; +@import './fix-windicss.less'; + +html, body { + margin: 0; + padding: 0; + height: 100%; + width: 100%; + box-sizing: border-box; +} + +div#app { + height: 100% +} + +h1, h2, h3, h4, h5, h6 { + margin-bottom: 0; +} + +.fs-desc{ + font-size: 12px; + color:#888888; + margin-left: 5px; + margin-right: 5px; +} + + + +.ant-btn-link { + height: 24px; +} + + +.ant-input-affix-wrapper { + padding: 4px 11px; +} + + +.anticon { + vertical-align: 0 !important; +} diff --git a/packages/ui/certd-client/src/style/fix-windicss.less b/packages/ui/certd-client/src/style/fix-windicss.less new file mode 100644 index 00000000..c4e284ec --- /dev/null +++ b/packages/ui/certd-client/src/style/fix-windicss.less @@ -0,0 +1,3 @@ +img.ant-image-preview-img{ + display: initial; +} diff --git a/packages/ui/certd-client/src/style/scroll.less b/packages/ui/certd-client/src/style/scroll.less new file mode 100644 index 00000000..67b7a33a --- /dev/null +++ b/packages/ui/certd-client/src/style/scroll.less @@ -0,0 +1,28 @@ +::-webkit-scrollbar { + width: 8px; + height: 8px; +} + +::-webkit-scrollbar-track { + width: 8px; + background: rgba(#101F1C, 0.1); + -webkit-border-radius: 2em; + -moz-border-radius: 2em; + border-radius: 2em; +} + +::-webkit-scrollbar-thumb { + // background-color: rgba(#101F1C, 0.5); + background-clip: padding-box; + min-height: 28px; + -webkit-border-radius: 2em; + -moz-border-radius: 2em; + border-radius: 2em; + background-color: #b3b3b3; + box-shadow: 0px 1px 1px #eee inset; +} + +::-webkit-scrollbar-thumb:hover { + + //background-color: rgba(#101F1C, 1); +} diff --git a/packages/ui/certd-client/src/style/theme/default.less b/packages/ui/certd-client/src/style/theme/default.less new file mode 100644 index 00000000..9b91b345 --- /dev/null +++ b/packages/ui/certd-client/src/style/theme/default.less @@ -0,0 +1,27 @@ +.ant-layout{ + background-color: @bg-color; +} +.ant-layout-header { + background-color: @bg-color +} +.ant-layout-sider { + background-color:@bg-color +} +.ant-menu{ + background-color: @bg-color; + &.ant-menu-submenu-popup{ + background-color: transparent; + } +} +.aside-menu{ + .ant-menu-submenu > .ant-menu{ + background-color:@bg-color + } + + .ant-menu-item-active{ + background-color: @bg-menu-item-color; + } + .ant-menu-item-selected{ + background-color: @bg-menu-item-color !important; + } +} diff --git a/packages/ui/certd-client/src/style/theme/index.less b/packages/ui/certd-client/src/style/theme/index.less new file mode 100644 index 00000000..d83434fc --- /dev/null +++ b/packages/ui/certd-client/src/style/theme/index.less @@ -0,0 +1,4 @@ +@primary-color: #1890ff; +// theme +@bg-color: #ebf1f6; +@bg-menu-item-color:hsla(0,0%,100%,.5); diff --git a/packages/ui/certd-client/src/style/transition.less b/packages/ui/certd-client/src/style/transition.less new file mode 100644 index 00000000..8ab0a269 --- /dev/null +++ b/packages/ui/certd-client/src/style/transition.less @@ -0,0 +1,36 @@ +//.v-enter-from, +//.v-leave-to { +// opacity: 0; +//} +// +//.v-leave-from, +//.v-enter-to { +// opacity: 1; +//} +// 过渡动画 横向渐变 +.fade-transverse-leave-active, +.fade-transverse-enter-active { + transition: all .5s; +} +.fade-transverse-enter-from { + opacity: 0; + transform: translateX(-30px); +} +.fade-transverse-leave-to { + opacity: 0; + transform: translateX(30px); +} + +// 过渡动画 缩放渐变 +.fade-scale-leave-active, +.fade-scale-enter-active { + transition: all .3s; +} +.fade-scale-enter { + opacity: 0; + transform: scale(1.2); +} +.fade-scale-leave-to { + opacity: 0; + transform: scale(0.8); +} diff --git a/packages/ui/certd-client/src/types/global.d.ts b/packages/ui/certd-client/src/types/global.d.ts new file mode 100644 index 00000000..d40bbd68 --- /dev/null +++ b/packages/ui/certd-client/src/types/global.d.ts @@ -0,0 +1,99 @@ +import type { + ComponentRenderProxy, + VNode, + ComponentPublicInstance, + FunctionalComponent, + PropType as VuePropType, +} from 'vue'; + +declare global { + const __APP_INFO__: { + pkg: { + name: string; + version: string; + dependencies: Recordable; + devDependencies: Recordable; + }; + lastBuildTime: string; + }; + declare interface Window { + // Global vue app instance + __APP__: App; + } + + // vue + declare type PropType = VuePropType; + + export type Writable = { + -readonly [P in keyof T]: T[P]; + }; + + declare type Nullable = T | null; + declare type NonNullable = T extends null | undefined ? never : T; + declare type Recordable = Record; + declare type ReadonlyRecordable = { + readonly [key: string]: T; + }; + declare type Indexable = { + [key: string]: T; + }; + declare type DeepPartial = { + [P in keyof T]?: DeepPartial; + }; + declare type TimeoutHandle = ReturnType; + declare type IntervalHandle = ReturnType; + + declare interface ChangeEvent extends Event { + target: HTMLInputElement; + } + + declare interface WheelEvent { + path?: EventTarget[]; + } + interface ImportMetaEnv extends ViteEnv { + __: unknown; + } + + declare interface ViteEnv { + VITE_PORT: number; + VITE_USE_MOCK: boolean; + VITE_USE_PWA: boolean; + VITE_PUBLIC_PATH: string; + VITE_PROXY: [string, string][]; + VITE_GLOB_APP_TITLE: string; + VITE_GLOB_APP_SHORT_NAME: string; + VITE_USE_CDN: boolean; + VITE_DROP_CONSOLE: boolean; + VITE_BUILD_COMPRESS: 'gzip' | 'brotli' | 'none'; + VITE_BUILD_COMPRESS_DELETE_ORIGIN_FILE: boolean; + VITE_LEGACY: boolean; + VITE_USE_IMAGEMIN: boolean; + VITE_GENERATE_UI: string; + } + + declare function parseInt(s: string | number, radix?: number): number; + + declare function parseFloat(string: string | number): number; + + namespace JSX { + // tslint:disable no-empty-interface + type Element = VNode; + // tslint:disable no-empty-interface + type ElementClass = ComponentRenderProxy; + interface ElementAttributesProperty { + $props: any; + } + interface IntrinsicElements { + [elem: string]: any; + } + interface IntrinsicAttributes { + [elem: string]: any; + } + } +} + +declare module 'vue' { + export type JSXComponent = + | { new (): ComponentPublicInstance } + | FunctionalComponent; +} diff --git a/packages/ui/certd-client/src/utils/index.ts b/packages/ui/certd-client/src/utils/index.ts new file mode 100644 index 00000000..7e3f9afe --- /dev/null +++ b/packages/ui/certd-client/src/utils/index.ts @@ -0,0 +1,12 @@ +import * as envs from "./util.env"; +import * as sites from "./util.site"; +import * as storages from "./util.storage"; +import * as commons from "./util.common"; +import * as mitt from "./util.mitt"; +export const util = { + ...envs, + ...sites, + ...storages, + ...commons, + ...mitt +}; diff --git a/packages/ui/certd-client/src/utils/util.common.ts b/packages/ui/certd-client/src/utils/util.common.ts new file mode 100644 index 00000000..ca20b8c3 --- /dev/null +++ b/packages/ui/certd-client/src/utils/util.common.ts @@ -0,0 +1,33 @@ +import _ from "lodash-es"; +export default { + arrayToMap(array) { + if (!array) { + return {}; + } + if (!_.isArray(array)) { + return array; + } + const map = {}; + for (const item of array) { + if (item.key) { + map[item.key] = item; + } + } + return map; + }, + mapToArray(map) { + if (!map) { + return []; + } + if (_.isArray(map)) { + return map; + } + const array: any = []; + for (const key in map) { + const item = map[key]; + item.key = key; + array.push(item); + } + return array; + } +}; diff --git a/packages/ui/certd-client/src/utils/util.env.ts b/packages/ui/certd-client/src/utils/util.env.ts new file mode 100644 index 00000000..d87db909 --- /dev/null +++ b/packages/ui/certd-client/src/utils/util.env.ts @@ -0,0 +1,40 @@ +import _ from "lodash-es"; +export function getEnvValue(key) { + // @ts-ignore + return import.meta.env["VITE_APP_" + key]; +} + +export class EnvConfig { + API; + MODE; + STORAGE; + TITLE; + PM_ENABLED; + constructor() { + this.init(); + } + + init() { + // @ts-ignore + _.forEach(import.meta.env, (value, key) => { + if (key.startsWith("VITE_APP")) { + key = key.replace("VITE_APP_", ""); + this[key] = value; + } + }); + // @ts-ignore + this.MODE = import.meta.env.MODE; + } + + get(key, defaultValue) { + return this[key] ?? defaultValue; + } + isDev() { + return this.MODE === "development" || this.MODE === "debug"; + } + isProd() { + return this.MODE === "production"; + } +} + +export const env = new EnvConfig(); diff --git a/packages/ui/certd-client/src/utils/util.mitt.ts b/packages/ui/certd-client/src/utils/util.mitt.ts new file mode 100644 index 00000000..be0f064f --- /dev/null +++ b/packages/ui/certd-client/src/utils/util.mitt.ts @@ -0,0 +1,2 @@ +import mitt from "mitt"; +export const mitter = mitt(); diff --git a/packages/ui/certd-client/src/utils/util.site.ts b/packages/ui/certd-client/src/utils/util.site.ts new file mode 100644 index 00000000..6305d396 --- /dev/null +++ b/packages/ui/certd-client/src/utils/util.site.ts @@ -0,0 +1,11 @@ +import { env } from "./util.env"; +export const site = { + /** + * @description 更新标题 + * @param {String} title 标题 + */ + title: function (titleText) { + const processTitle = env.TITLE || "FsAdmin"; + window.document.title = `${processTitle}${titleText ? ` | ${titleText}` : ""}`; + } +}; diff --git a/packages/ui/certd-client/src/utils/util.storage.ts b/packages/ui/certd-client/src/utils/util.storage.ts new file mode 100644 index 00000000..b9342da6 --- /dev/null +++ b/packages/ui/certd-client/src/utils/util.storage.ts @@ -0,0 +1,113 @@ +import { env } from "./util.env"; +function isNullOrUnDef(value) { + return value == null; +} +const DEFAULT_CACHE_TIME = 60 * 60 * 24 * 7; +export interface CreateStorageParams { + prefixKey: string; + storage: Storage; + timeout?: number; +} + +/** + *Cache class + *Construction parameters can be passed into sessionStorage, localStorage, + * @class Cache + * @example + */ +export class WebStorage { + private storage: Storage; + private prefixKey?: string; + private timeout?: number; + /** + * + * @param option + */ + constructor(option: Partial) { + this.storage = option.storage ?? localStorage; + this.prefixKey = option.prefixKey ?? getStorageShortName(); + this.timeout = option.timeout ?? DEFAULT_CACHE_TIME; + } + + private getKey(key: string) { + return `${this.prefixKey}${key}`.toUpperCase(); + } + + /** + * + * Set cache + * @param {string} key + * @param {*} value + * @param expire + * @expire Expiration time in seconds + * @memberof Cache + */ + set(key: string, value: any, expire: number | undefined = this.timeout) { + const stringData = JSON.stringify({ + value, + time: Date.now(), + expire: expire != null ? new Date().getTime() + expire * 1000 : null + }); + this.storage.setItem(this.getKey(key), stringData); + } + + /** + *Read cache + * @param {string} key + * @param def + * @memberof Cache + */ + get(key: string, def: any = null): any { + const val = this.storage.getItem(this.getKey(key)); + if (!val) return def; + + try { + const data = JSON.parse(val); + const { value, expire } = data; + if (isNullOrUnDef(expire) || expire >= new Date().getTime()) { + return value; + } + this.remove(key); + } catch (e) { + return def; + } + } + + /** + * Delete cache based on key + * @param {string} key + * @memberof Cache + */ + remove(key: string) { + this.storage.removeItem(this.getKey(key)); + } + + /** + * Delete all caches of this instance + */ + clear(): void { + this.storage.clear(); + } +} +export const createStorage = (option: Partial = {}): WebStorage => { + return new WebStorage(option); +}; + +export type Options = Partial; + +function getStorageShortName() { + return env.MODE + "_" + env.get("STORAGE", "certd") + "_"; +} + +export const createSessionStorage = (options: Options = {}): WebStorage => { + return createStorage({ storage: sessionStorage, ...options }); +}; + +export const createLocalStorage = (options: Options = {}): WebStorage => { + return createStorage({ storage: localStorage, timeout: DEFAULT_CACHE_TIME, ...options }); +}; + +export const SessionStorage = createSessionStorage(); +export const LocalStorage = createLocalStorage(); + +export default WebStorage; diff --git a/packages/ui/certd-client/src/views/crud/advanced/big-data/api.js b/packages/ui/certd-client/src/views/crud/advanced/big-data/api.js new file mode 100644 index 00000000..a2e187ae --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/big-data/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/AdvancedBigData"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/advanced/big-data/crud.jsx b/packages/ui/certd-client/src/views/crud/advanced/big-data/crud.jsx new file mode 100644 index 00000000..d66f65d8 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/big-data/crud.jsx @@ -0,0 +1,170 @@ +import * as api from "./api"; +import { message } from "ant-design-vue"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + return { + output: {}, + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + table: { + scroll: { + //启用横向滚动条,设置一个大于所有列宽之和的值,一般大于表格宽度 + x: 2400 + } + }, + pagination: { + pageSize: 100 + }, + rowHandle: { + fixed: "right" + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + text: { + title: "文本", + type: "text" + }, + dict1: { + title: "字典1", + type: "dict-select", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?from=dict1" + }) + }, + dict2: { + title: "字典2", + type: "dict-select", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?from=dict2" + }) + }, + dict3: { + title: "字典3", + type: "dict-select", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?from=dict3" + }) + }, + dict4: { + title: "字典4", + type: "dict-select", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?from=dict4" + }) + }, + dict5: { + title: "字典5", + type: "dict-select", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?from=dict5" + }) + }, + dict6: { + title: "字典6", + type: "dict-select", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?from=dict6" + }) + }, + dict7: { + title: "字典7", + type: "dict-select", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?from=dict7" + }) + }, + dict8: { + title: "字典8", + type: "dict-select", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?from=dict8" + }) + }, + dict9: { + title: "字典9", + type: "dict-select", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?from=dict9" + }) + }, + dict10: { + title: "字典10", + type: "dict-select", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?from=dict10" + }) + }, + text1: { + title: "文本", + type: "text" + }, + text2: { + title: "文本", + type: "text" + }, + text3: { + title: "文本", + type: "text" + }, + text4: { + title: "文本", + type: "text" + }, + text5: { + title: "文本", + type: "text" + }, + text6: { + title: "文本", + type: "text" + }, + text7: { + title: "文本", + type: "text" + }, + text8: { + title: "文本", + type: "text" + }, + text9: { + title: "文本", + type: "text" + }, + text10: { + title: "文本", + type: "text" + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/advanced/big-data/index.vue b/packages/ui/certd-client/src/views/crud/advanced/big-data/index.vue new file mode 100644 index 00000000..91a4914c --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/big-data/index.vue @@ -0,0 +1,43 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/advanced/big-data/mock.js b/packages/ui/certd-client/src/views/crud/advanced/big-data/mock.js new file mode 100644 index 00000000..a166ac9d --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/big-data/mock.js @@ -0,0 +1,126 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "AdvancedBigData", + idGenerator: 0, + copyTimes: 1000 +}; +const list = [ + { + text: "测试文本", + dict1: "1", + dict2: "1", + dict3: "2", + dict4: "1", + dict5: "2", + dict6: "1", + dict7: "1", + dict8: "1", + text1: "测试文本1", + text2: "测试文本2", + text3: "测试文本3", + text4: "测试文本4", + text5: "测试文本5", + text6: "测试文本6", + text7: "测试文本7", + text8: "测试文本8", + dict9: "2", + dict10: "1", + dict11: "2", + dict12: "1" + }, + { + text: "测试文本", + dict1: "1", + dict2: "1", + dict3: "2", + dict4: "1", + dict5: "2", + dict6: "1", + dict7: "1", + dict8: "1", + text1: "测试文本1", + text2: "测试文本2", + text3: "测试文本3", + text4: "测试文本4", + text5: "测试文本5", + text6: "测试文本6", + text7: "测试文本7", + text8: "测试文本8", + dict9: "2", + dict10: "1", + dict11: "2", + dict12: "1" + }, + { + text: "测试文本", + dict1: "1", + dict2: "1", + dict3: "2", + dict4: "1", + dict5: "2", + dict6: "1", + dict7: "1", + dict8: "1", + text1: "测试文本1", + text2: "测试文本2", + text3: "测试文本3", + text4: "测试文本4", + text5: "测试文本5", + text6: "测试文本6", + text7: "测试文本7", + text8: "测试文本8", + dict9: "2", + dict10: "1", + dict11: "2", + dict12: "1" + }, + { + text: "测试文本", + dict1: "1", + dict2: "1", + dict3: "2", + dict4: "1", + dict5: "2", + dict6: "1", + dict7: "1", + dict8: "1", + text1: "测试文本1", + text2: "测试文本2", + text3: "测试文本3", + text4: "测试文本4", + text5: "测试文本5", + text6: "测试文本6", + text7: "测试文本7", + text8: "测试文本8", + dict9: "2", + dict10: "1", + dict11: "2", + dict12: "1" + }, + { + text: "测试文本", + dict1: "1", + dict2: "1", + dict3: "2", + dict4: "1", + dict5: "2", + dict6: "1", + dict7: "1", + dict8: "1", + text1: "测试文本1", + text2: "测试文本2", + text3: "测试文本3", + text4: "测试文本4", + text5: "测试文本5", + text6: "测试文本6", + text7: "测试文本7", + text8: "测试文本8", + dict9: "2", + dict10: "1", + dict11: "2", + dict12: "1" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/advanced/from-backend/api.js b/packages/ui/certd-client/src/views/crud/advanced/from-backend/api.js new file mode 100644 index 00000000..ae38d293 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/from-backend/api.js @@ -0,0 +1,48 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/AdvancedFromBackend"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} +export function GetCrud() { + return request({ + url: apiPrefix + "/crud", + method: "get" + }); +} diff --git a/packages/ui/certd-client/src/views/crud/advanced/from-backend/crud-backend.js b/packages/ui/certd-client/src/views/crud/advanced/from-backend/crud-backend.js new file mode 100644 index 00000000..abcf8ef1 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/from-backend/crud-backend.js @@ -0,0 +1,29 @@ +export const crudOptions = ` + ({expose,dict}) => { + return { + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + } + } + } +} + + +`; diff --git a/packages/ui/certd-client/src/views/crud/advanced/from-backend/crud.jsx b/packages/ui/certd-client/src/views/crud/advanced/from-backend/crud.jsx new file mode 100644 index 00000000..a577b88d --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/from-backend/crud.jsx @@ -0,0 +1,27 @@ +import * as api from "./api"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/advanced/from-backend/index.vue b/packages/ui/certd-client/src/views/crud/advanced/from-backend/index.vue new file mode 100644 index 00000000..bec75930 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/from-backend/index.vue @@ -0,0 +1,45 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/advanced/from-backend/mock.js b/packages/ui/certd-client/src/views/crud/advanced/from-backend/mock.js new file mode 100644 index 00000000..2f802d45 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/from-backend/mock.js @@ -0,0 +1,35 @@ +import mockUtil from "/src/mock/base"; +import { crudOptions } from "./crud-backend"; +const options = { + name: "AdvancedFromBackend", + idGenerator: 0 +}; +const list = [ + { + radio: "1" + }, + { + radio: "2" + }, + { + radio: "0" + } +]; + +options.list = list; +options.copyTimes = 1000; +const mock = mockUtil.buildMock(options); + +mock.push({ + path: "/AdvancedFromBackend/crud", + method: "get", + handle(req) { + return { + code: 0, + msg: "success", + data: crudOptions + }; + } +}); + +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/advanced/in-dialog/crud/api.js b/packages/ui/certd-client/src/views/crud/advanced/in-dialog/crud/api.js new file mode 100644 index 00000000..236e922a --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/in-dialog/crud/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/AdvancedInDialog"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/advanced/in-dialog/crud/crud.jsx b/packages/ui/certd-client/src/views/crud/advanced/in-dialog/crud/crud.jsx new file mode 100644 index 00000000..cde2c0c2 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/in-dialog/crud/crud.jsx @@ -0,0 +1,106 @@ +import * as api from "./api"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + name: { + title: "姓名", + type: "text", //虽然不写也能正确显示组件,但不建议省略它 + search: { show: true }, + form: { + component: { + maxlength: 20 + } + } + }, + search: { + title: "搜索", + type: "text", + form: { + component: { + addonAfter: "后置", + suffix: "suffix", + children: { + addonBefore() { + return ; + } + } + } + } + }, + password: { + title: "密码", + type: "password", + column: { + //一般密码不显示在列里面 + show: false + } + }, + intro: { + title: "简介", + type: "textarea", + form: { + component: { showWordLimit: true, maxlength: 200 } + }, + column: { + ellipsis: true + } + }, + render: { + title: "复杂输入(render)", + form: { + title: "复杂输入", + component: { + render(context) { + console.log("context scope", context); + return ( + + + + + ); + } + } + } + }, + render2: { + title: "我的值是由复杂输入列输入的", + column: { + width: "300px" + }, + form: { + show: false + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/advanced/in-dialog/crud/index.vue b/packages/ui/certd-client/src/views/crud/advanced/in-dialog/crud/index.vue new file mode 100644 index 00000000..5b3591ef --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/in-dialog/crud/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/advanced/in-dialog/crud/mock.js b/packages/ui/certd-client/src/views/crud/advanced/in-dialog/crud/mock.js new file mode 100644 index 00000000..31a5c561 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/in-dialog/crud/mock.js @@ -0,0 +1,40 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "AdvancedInDialog", + idGenerator: 0 +}; +const list = [ + { + name: "王小虎", + date: "2016-05-02", + status: "0", + province: "1", + avatar: "https://alicdn.antdv.com/vue.png", + show: true, + city: "sz", + address: "123123", + zip: "518000", + intro: "王小虎是element-plus的table示例出现的名字" + }, + { + name: "张三", + date: "2016-05-04", + status: "1", + province: "2" + }, + { + name: "李四", + date: 2232433534511, + status: "1", + province: "0" + }, + { + name: "王五", + date: "2016-05-03", + status: "2", + province: "wh,gz" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/advanced/in-dialog/index.vue b/packages/ui/certd-client/src/views/crud/advanced/in-dialog/index.vue new file mode 100644 index 00000000..64ac7713 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/in-dialog/index.vue @@ -0,0 +1,37 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/advanced/linkage/api.js b/packages/ui/certd-client/src/views/crud/advanced/linkage/api.js new file mode 100644 index 00000000..bbc69cc2 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/linkage/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FormLinkage"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/advanced/linkage/crud.jsx b/packages/ui/certd-client/src/views/crud/advanced/linkage/crud.jsx new file mode 100644 index 00000000..6fe18540 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/linkage/crud.jsx @@ -0,0 +1,118 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + rowHandle: { + align: "center" + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + province: { + title: "省", + type: "dict-select", + search: { + show: true + }, + dict: dict({ + url: "/mock/linkage/province", + value: "id", + cache: true + }), + form: { + valueChange({ form, value, getComponentRef }) { + form.city = undefined; // 将“city”的值置空 + form.county = undefined; // 将“county”的值置空 + if (value) { + getComponentRef("city").reloadDict(); // 执行city的select组件的reloadDict()方法,触发“city”重新加载字典 + } + } + } + }, + city: { + title: "市", + type: "dict-select", + search: { + show: true + }, + dict: dict({ + cache: true, + prototype: true, + // url() 改成构建url,返回一个url + url({ form }) { + if (form && form.province != null) { + // 本数据字典的url是通过前一个select的选项决定的 + return `/mock/linkage/city?province=${form.province}`; + } + return undefined; // 返回undefined 将不加载字典 + }, + value: "id" + }), + form: { + // 注释同上 + valueChange({ value, form, getComponentRef }) { + if (value) { + form.county = undefined; // 将county的value置空 + const countySelect = getComponentRef("county"); + if (form && form.province && form.city) { + countySelect.reloadDict(); // 重新加载字典项 + } else { + countySelect.clearDict(); // 清空选项 + } + } + } + } + }, + county: { + title: "区", + type: "dict-select", + search: { + show: true + }, + dict: dict({ + value: "id", + cache: true, + prototype: true, + url({ form }) { + if (form && form.province != null && form.city != null) { + return `/mock/linkage/county?province=${form.province} &city=${form.city}`; + } + return undefined; + } + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/advanced/linkage/index.vue b/packages/ui/certd-client/src/views/crud/advanced/linkage/index.vue new file mode 100644 index 00000000..48faf05b --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/linkage/index.vue @@ -0,0 +1,38 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/advanced/linkage/mock.js b/packages/ui/certd-client/src/views/crud/advanced/linkage/mock.js new file mode 100644 index 00000000..8e42b2d5 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/linkage/mock.js @@ -0,0 +1,129 @@ +import mockUtil from "/src/mock/base"; +import _ from "lodash-es"; +const options = { + name: "FormLinkage", + idGenerator: 0 +}; +const list = [ + { + province: 10000, + city: 100003, + county: 100004 + }, + { + province: 10010, + city: 100113, + county: 100115 + } +]; +const tree = [ + { + id: 10000, + label: "北京市", + children: [ + { + id: 100003, + label: "北京市辖区", + children: [ + { id: 100004, label: "东城区" }, + { id: 100005, label: "西城区" } + ] + }, + { + id: 100103, + label: "北京郊区", + children: [ + { id: 100104, label: "东郊" }, + { id: 100105, label: "西郊" } + ] + } + ] + }, + { + id: 10010, + label: "天津市", + children: [ + { + id: 100013, + label: "天津市辖区", + children: [ + { id: 100014, label: "天津湾" }, + { id: 100015, label: "渤海湾" } + ] + }, + { + id: 100113, + label: "天津市郊区", + children: [ + { id: 100114, label: "天津湾郊区" }, + { id: 100115, label: "渤海湾郊区" } + ] + } + ] + } +]; + +options.list = list; +options.copyTimes = 1000; +const mock = mockUtil.buildMock(options); + +function omitChildren(orignalListt) { + const list = []; + orignalListt.forEach((item) => { + list.push(_.omit(item, "children")); + }); + return list; +} +mock.push({ + path: "/mock/linkage/province", + method: "get", + handle() { + const list = omitChildren(tree); + return { + code: 0, + msg: "success", + data: list + }; + } +}); + +mock.push({ + path: "/mock/linkage/city", + method: "get", + handle(req) { + const province = parseInt(req.params.province); + const a = tree.filter((item) => { + return item.id === province; + }); + const list = omitChildren(a[0].children); + return { + code: 0, + msg: "success", + data: list + }; + } +}); + +mock.push({ + path: "/mock/linkage/county", + method: "get", + handle(req) { + const province = parseInt(req.params.province); + const a = tree.filter((item) => { + return item.id === province; + }); + const city = parseInt(req.params.city); + const b = a[0].children.filter((item) => { + return item.id === city; + }); + + const list = omitChildren(b[0].children); + return { + code: 0, + msg: "success", + data: list + }; + } +}); + +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/advanced/local-pagination/api.js b/packages/ui/certd-client/src/views/crud/advanced/local-pagination/api.js new file mode 100644 index 00000000..457dac6d --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/local-pagination/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/AdvancedLocalPagination"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/advanced/local-pagination/crud.jsx b/packages/ui/certd-client/src/views/crud/advanced/local-pagination/crud.jsx new file mode 100644 index 00000000..e4989bee --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/local-pagination/crud.jsx @@ -0,0 +1,101 @@ +import * as api from "./api"; +import _ from "lodash-es"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose, localDataRef }) { + const pageRequest = async ({ page, query }) => { + //总数据 + let data = localDataRef.value; + //获取请求参数 + const limit = page.limit; + let offset = page.offset; + data = data.filter((item) => { + // 根据你的业务,编写你的本地查询逻辑 + // text改成你的查询字段 + if (query.status && item.status !== query.status) { + return false; + } + return true; + }); + + // 本地分页 + const start = offset; + let end = offset + limit; + if (data.length < end) { + end = data.length; + } + const records = data.slice(start, end); + + // 构造返回结果 + return { + offset, + limit, + total: localDataRef.value.length, + records + }; + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + await api.UpdateObj(form); + //更新本地数据 + const tableData = localDataRef.value; + for (const item of tableData) { + if (item.id === form.id) { + _.merge(item, form); + } + } + }; + + const addRequest = async ({ form }) => { + const id = await api.AddObj(form); + //本地添加 + form.id = id; + localDataRef.value.unshift(form); + return id; + }; + + const delRequest = async ({ row }) => { + await api.DelObj(row.id); + //本地删除那一条记录 + const tableData = localDataRef.value; + let index = 0; + for (const item of tableData) { + if (item.id === row.id) { + localDataRef.value.splice(index, 1); + } + index++; + } + }; + + return { + output: {}, + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + status: { + title: "状态", + search: { show: true }, + type: "dict-select", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/advanced/local-pagination/index.vue b/packages/ui/certd-client/src/views/crud/advanced/local-pagination/index.vue new file mode 100644 index 00000000..d48a680e --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/local-pagination/index.vue @@ -0,0 +1,57 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/advanced/local-pagination/mock.js b/packages/ui/certd-client/src/views/crud/advanced/local-pagination/mock.js new file mode 100644 index 00000000..120c2a63 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/local-pagination/mock.js @@ -0,0 +1,19 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "AdvancedLocalPagination", + idGenerator: 0 +}; +const list = [ + { + status: "1" + }, + { + status: "2" + }, + { + status: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/advanced/nest/api.js b/packages/ui/certd-client/src/views/crud/advanced/nest/api.js new file mode 100644 index 00000000..b18db901 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/nest/api.js @@ -0,0 +1,50 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/AdvancedNest"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} + +export function BatchDelete(ids) { + return request({ + url: apiPrefix + "/batchDelete", + method: "post", + data: { ids } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/advanced/nest/aside-table/api.js b/packages/ui/certd-client/src/views/crud/advanced/nest/aside-table/api.js new file mode 100644 index 00000000..3a8a4a1b --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/nest/aside-table/api.js @@ -0,0 +1,50 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/AdvancedAside"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} + +export function BatchDelete(ids) { + return request({ + url: apiPrefix + "/batchDelete", + method: "post", + data: { ids } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/advanced/nest/aside-table/crud.jsx b/packages/ui/certd-client/src/views/crud/advanced/nest/aside-table/crud.jsx new file mode 100644 index 00000000..567715c6 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/nest/aside-table/crud.jsx @@ -0,0 +1,56 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + return { + crudOptions: { + pagination: { + showSizeChanger: false, // antdv + showQuickJumper: false // antdv + }, + request: { + pageRequest: api.GetList, + addRequest, + editRequest, + delRequest + }, + toolbar: { + compact: false + }, + rowHandle: { + width: "230px" + }, + table: {}, + columns: { + gradeId: { + title: "年级Id", + search: { show: true }, + type: "number", + column: { + width: 80, + align: "center", + sortable: true + } + }, + class: { + title: "班级", + search: { show: false }, + type: "text", + column: { + sortable: true + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/advanced/nest/aside-table/index.vue b/packages/ui/certd-client/src/views/crud/advanced/nest/aside-table/index.vue new file mode 100644 index 00000000..9a198b9e --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/nest/aside-table/index.vue @@ -0,0 +1,43 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/advanced/nest/aside-table/mock.js b/packages/ui/certd-client/src/views/crud/advanced/nest/aside-table/mock.js new file mode 100644 index 00000000..2d70c579 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/nest/aside-table/mock.js @@ -0,0 +1,26 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "AdvancedAside", + idGenerator: 0 +}; +const list = [ + { + class: "一班", + gradeId: 1 + }, + { + class: "二班", + gradeId: 1 + }, + { + class: "三班", + gradeId: 2 + }, + { + class: "四班", + gradeId: 2 + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/advanced/nest/crud.jsx b/packages/ui/certd-client/src/views/crud/advanced/nest/crud.jsx new file mode 100644 index 00000000..b42ba5c8 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/nest/crud.jsx @@ -0,0 +1,101 @@ +import * as api from "./api"; +import { ref, shallowRef } from "vue"; +import SubTable from "./sub-table/index.vue"; +import { compute } from "@fast-crud/fast-crud"; +export default function ({ expose, asideTableRef }) { + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + const currentRow = ref(); + + const onCurrentRowChange = (id) => { + currentRow.value = id; + asideTableRef.value.setSearchFormData({ form: { gradeId: id } }); + asideTableRef.value.doRefresh(); + }; + return { + crudOptions: { + table: { + customRow(record, index) { + const clazz = record.id === currentRow.value ? "fs-current-row" : ""; + return { + onClick() { + onCurrentRowChange(record.id); + }, + class: clazz + }; + } + }, + pagination: { + showSizeChanger: false, // antdv + showQuickJumper: false // antdv + }, + form: { + wrapper: { + is: "a-drawer" + } + }, + request: { + pageRequest: api.GetList, + addRequest, + editRequest, + delRequest + }, + rowHandle: { + width: "240px" + }, + toolbar: { + compact: false + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + grade: { + title: "年级", + search: { show: true }, + type: "text", + column: { + sortable: true + } + }, + nestId: { + title: "嵌套表格", + //复合字段类型 + type: ["number", "colspan"], + form: { + // 嵌套表格字段 + rules: [{ required: true, message: "请选择用户" }], + component: { + //局部引用子表格,要用shallowRef包裹 + name: shallowRef(SubTable), + vModel: "modelValue", + gradeId: compute(({ form }) => { + return form.id; + }) + } + // antdv 的跨列配置,需要配置如下三个, 可以通过colspan简化 + // col: { span: 24 }, + // labelCol: { span: 2 }, + // wrapperCol: { span: 21 } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/advanced/nest/index.vue b/packages/ui/certd-client/src/views/crud/advanced/nest/index.vue new file mode 100644 index 00000000..5fa4b445 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/nest/index.vue @@ -0,0 +1,59 @@ + + + + diff --git a/packages/ui/certd-client/src/views/crud/advanced/nest/mock.js b/packages/ui/certd-client/src/views/crud/advanced/nest/mock.js new file mode 100644 index 00000000..709699d2 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/nest/mock.js @@ -0,0 +1,22 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "AdvancedNest", + idGenerator: 0 +}; +const list = [ + { + grade: "一年级", + nestId: 1 + }, + { + grade: "二年级", + nestId: 2 + }, + { + grade: "三年级", + nestId: 3 + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/advanced/nest/sub-table/api.js b/packages/ui/certd-client/src/views/crud/advanced/nest/sub-table/api.js new file mode 100644 index 00000000..167a31de --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/nest/sub-table/api.js @@ -0,0 +1,50 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/AdvancedSubTable"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} + +export function BatchDelete(ids) { + return request({ + url: apiPrefix + "/batchDelete", + method: "post", + data: { ids } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/advanced/nest/sub-table/crud.jsx b/packages/ui/certd-client/src/views/crud/advanced/nest/sub-table/crud.jsx new file mode 100644 index 00000000..ad5faa1e --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/nest/sub-table/crud.jsx @@ -0,0 +1,62 @@ +import * as api from "./api"; +export default function ({ expose, props, ctx }) { + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + return { + crudOptions: { + table: { + customRow(record, index) { + const clazz = record.id === props.modelValue ? "fs-current-row" : ""; + return { + onClick() { + ctx.emit("update:modelValue", record.id); + }, + class: clazz + }; + } + }, + request: { + pageRequest: api.GetList, + addRequest, + editRequest, + delRequest + }, + search: { show: false }, + form: { + wrapper: { + is: "a-drawer" + } + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + name: { + title: "用户姓名", + search: { show: true }, + type: "text", + column: { + sortable: true + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/advanced/nest/sub-table/index.vue b/packages/ui/certd-client/src/views/crud/advanced/nest/sub-table/index.vue new file mode 100644 index 00000000..fb928438 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/nest/sub-table/index.vue @@ -0,0 +1,61 @@ + + + + diff --git a/packages/ui/certd-client/src/views/crud/advanced/nest/sub-table/mock.js b/packages/ui/certd-client/src/views/crud/advanced/nest/sub-table/mock.js new file mode 100644 index 00000000..726a628a --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/advanced/nest/sub-table/mock.js @@ -0,0 +1,19 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "AdvancedSubTable", + idGenerator: 0 +}; +const list = [ + { + name: "张三" + }, + { + name: "李四" + }, + { + name: "王五" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/basis/column-merge-plugin/api.js b/packages/ui/certd-client/src/views/crud/basis/column-merge-plugin/api.js new file mode 100644 index 00000000..af612a7a --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/column-merge-plugin/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/BasisColumnMergePlugin"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/basis/column-merge-plugin/crud.jsx b/packages/ui/certd-client/src/views/crud/basis/column-merge-plugin/crud.jsx new file mode 100644 index 00000000..40a9cc8c --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/column-merge-plugin/crud.jsx @@ -0,0 +1,69 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; + +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + return { + output: {}, + crudOptions: { + settings: { + viewFormUseCellComponent: true + }, + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + text: { + title: "text", + type: "text" + }, + readonly: { + title: "只读字段", + type: "text", + readonly: true + }, + useCell: { + title: "查看使用cell组件", + type: "dict-select", + readonly: true, + dict: dict({ + url: "/mock/dicts/OpenStatusEnum" + }), + viewForm: { + component: { + vModel: "modelValue" + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/basis/column-merge-plugin/index.vue b/packages/ui/certd-client/src/views/crud/basis/column-merge-plugin/index.vue new file mode 100644 index 00000000..186aa036 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/column-merge-plugin/index.vue @@ -0,0 +1,34 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/basis/column-merge-plugin/mock.js b/packages/ui/certd-client/src/views/crud/basis/column-merge-plugin/mock.js new file mode 100644 index 00000000..a36687c6 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/column-merge-plugin/mock.js @@ -0,0 +1,25 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "BasisColumnMergePlugin", + idGenerator: 0 +}; +const list = [ + { + text: "点击右边查看按钮看效果", + readonly: "我是只读", + useCell: "1" + }, + { + text: "点击编辑按钮查看效果", + readonly: "我是只读", + useCell: "2" + }, + { + text: "正常字段", + readonly: "我是只读", + useCell: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/basis/columns-set/api.js b/packages/ui/certd-client/src/views/crud/basis/columns-set/api.js new file mode 100644 index 00000000..2d20318f --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/columns-set/api.js @@ -0,0 +1,50 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/BasisColumnsSet"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} + +export function BatchDelete(ids) { + return request({ + url: apiPrefix + "/batchDelete", + method: "post", + data: { ids } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/basis/columns-set/crud.jsx b/packages/ui/certd-client/src/views/crud/basis/columns-set/crud.jsx new file mode 100644 index 00000000..559e49e3 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/columns-set/crud.jsx @@ -0,0 +1,69 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +import { ref } from "vue"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + toolbar: { + columnsFilter: { + mode: "default" + } + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + }, + disabled: { + title: "列设置禁用", + type: "text", + column: { + columnSetDisabled: true + } + }, + hidden: { + title: "列设置隐藏", + type: "text", + column: { + columnSetShow: false + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/basis/columns-set/index.vue b/packages/ui/certd-client/src/views/crud/basis/columns-set/index.vue new file mode 100644 index 00000000..a5436107 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/columns-set/index.vue @@ -0,0 +1,52 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/basis/columns-set/mock.js b/packages/ui/certd-client/src/views/crud/basis/columns-set/mock.js new file mode 100644 index 00000000..90154b73 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/columns-set/mock.js @@ -0,0 +1,19 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "BasisColumnsSet", + idGenerator: 0 +}; +const list = [ + { + radio: "1" + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/basis/compute-more/api.js b/packages/ui/certd-client/src/views/crud/basis/compute-more/api.js new file mode 100644 index 00000000..39c56ba1 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/compute-more/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FormComputeMore"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/basis/compute-more/crud.jsx b/packages/ui/certd-client/src/views/crud/basis/compute-more/crud.jsx new file mode 100644 index 00000000..92ccdee8 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/compute-more/crud.jsx @@ -0,0 +1,79 @@ +import * as api from "./api"; +import { requestForMock } from "/src/api/service"; +import { useCompute } from "@fast-crud/fast-crud"; +import { message } from "ant-design-vue"; +import { ref, computed } from "vue"; +const { asyncCompute, compute } = useCompute(); +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + //普通的ref引用,可以动态切换配置 + const defValueRef = ref("我是动态的默认值"); + const defValueComputed = computed(() => { + return defValueRef.value; + }); + return { + output: { + defValueRef, + defValueComputed + }, + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + table: { + scroll: { + x: 1500 + } + }, + form: { + labelCol: { span: 8 }, + wrapperCol: { span: 14 } + }, + rowHandle: { + fixed: "right", + align:'center', + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + defValue: { + title: "默认值", + type: "text", + search: { show: true, value: null }, + form: { + // form.value不支持asyncCompute + // 假如你的默认值异步获取的,那么你自己必须保证先异步计算完成之后,才能打开对话框。 + // 因为在打开对话框时,默认值就必须得设置好。 + value: defValueRef + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/basis/compute-more/index.vue b/packages/ui/certd-client/src/views/crud/basis/compute-more/index.vue new file mode 100644 index 00000000..01d9da38 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/compute-more/index.vue @@ -0,0 +1,43 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/basis/compute-more/mock.js b/packages/ui/certd-client/src/views/crud/basis/compute-more/mock.js new file mode 100644 index 00000000..ee602acf --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/compute-more/mock.js @@ -0,0 +1,32 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FormComputeMore", + idGenerator: 0 +}; +const list = [ + { + ref: "根据showRef显示", + compute: true, + status: "1", + remote: "2", + shower: "---> 点右边编辑查看示例效果", + remote2: "2", + editable: true + }, + { + compute: false, + status: "2", + remote: "0", + remote2: "2", + editable: false + }, + { + compute: true, + status: "0", + remote2: "2", + editable: true + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/basis/compute/api.js b/packages/ui/certd-client/src/views/crud/basis/compute/api.js new file mode 100644 index 00000000..c8ec9fc8 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/compute/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FormCompute"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/basis/compute/crud.jsx b/packages/ui/certd-client/src/views/crud/basis/compute/crud.jsx new file mode 100644 index 00000000..0f450f13 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/compute/crud.jsx @@ -0,0 +1,211 @@ +import * as api from "./api"; +import { requestForMock } from "/src/api/service"; +import { useCompute } from "@fast-crud/fast-crud"; +import { message } from "ant-design-vue"; +import { ref, computed } from "vue"; +const { asyncCompute, compute } = useCompute(); +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + //普通的ref引用,可以动态切换配置 + const showRef = ref(false); + const showTableRef = ref(true); + const showTableComputed = computed(() => { + return showTableRef.value; + }); + + const columnComponentShowRef = ref(true); + const columnComponentShowComputed = computed(() => { + return columnComponentShowRef.value; + }); + + return { + output: { + showRef, + showTableRef, + columnComponentShowRef + }, + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + table: { + scroll: { + x: 1500 + }, + //通过switch动态显隐table + show: showTableComputed //不仅支持computed,直接传showTableRef也是可以的 + }, + form: { + labelCol: { span: 8 }, + wrapperCol: { span: 14 } + }, + rowHandle: { + fixed: "right", + buttons: { + edit: { + show: compute(({ row }) => { + return row.editable; + }) + }, + remove: { + show: compute(({ row }) => { + return row.editable; + }) + } + } + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50, + resizable: true + }, + form: { + show: false + } + }, + refSwitch: { + title: "ref引用切换", + type: "text", + form: { + helper: "点我切换右边的输入框显示" + } + }, + ref: { + title: "根据ref引用显示", + type: ["text"], + form: { + component: { + show: showRef + }, + helper: "我会根据showRef进行显隐" + } + }, + compute: { + title: "compute", + search: { show: false }, + type: "text", + column: { + show: columnComponentShowComputed, + columnSetDisabled: true, //这里采用自定义控制显隐,那么列设置里面就要禁用 + // columnSetShow: false, //直接不在列设置里面显示也行 + component: { + name: "a-switch", + vModel: "checked" + } + }, + form: { + component: { + name: "a-switch", + vModel: "checked" + }, + helper: "点我触发动态计算" + } + }, + shower: { + title: "根据compute显示", + search: { show: false }, + type: "button", + form: { + component: { + show: compute(({ form }) => { + return form.compute; + }) + } + }, + column: { + width: 250, + resizable: true, + component: { + show: compute(({ row }) => { + return row.compute; + }) + } + } + }, + remote: { + title: "asyncCompute", + search: { show: true }, + type: "text", + form: { + component: { + name: "a-select", + vModel: "value", + placeholder: "异步计算远程获取options", + options: asyncCompute({ + async asyncFn(watchValue, context) { + const url = "/mock/dicts/OpenStatusEnum?remote"; + return await requestForMock({ url }); + } + }) + }, + helper: "我的options是异步计算远程获取的,只会获取一次" + } + }, + remote2: { + title: "监听switch触发异步计算", + search: { show: false }, + type: "text", + form: { + component: { + name: "a-select", + vModel: "value", + placeholder: "异步计算远程获取options", + options: asyncCompute({ + watch({ form }) { + return form.compute; + }, + async asyncFn(watchValue) { + message.info("监听switch,触发远程获取options"); + const url = watchValue + ? "/mock/dicts/OpenStatusEnum?remote" + : "/mock/dicts/moreOpenStatusEnum?remote"; + return await requestForMock({ url }); + } + }) + }, + helper: "监听其他属性修改后,触发重新计算" + }, + column: { + width: 200 + } + }, + editable: { + title: "可编辑", + search: { show: false }, + type: "text", + column: { + fixed: "right", + component: { + name: "a-switch", + vModel: "checked" + } + }, + form: { + show: false + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/basis/compute/index.vue b/packages/ui/certd-client/src/views/crud/basis/compute/index.vue new file mode 100644 index 00000000..d7408935 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/compute/index.vue @@ -0,0 +1,60 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/basis/compute/mock.js b/packages/ui/certd-client/src/views/crud/basis/compute/mock.js new file mode 100644 index 00000000..b4c21d85 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/compute/mock.js @@ -0,0 +1,34 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FormCompute", + idGenerator: 0 +}; +const list = [ + { + ref: "根据showRef显示", + compute: true, + status: "1", + remote: "2", + shower: "---> 点右边编辑查看示例效果", + remote2: "2", + editable: true + }, + { + compute: false, + shower: "---> 点右边编辑查看示例效果", + status: "2", + remote: "0", + remote2: "2", + editable: false + }, + { + compute: true, + shower: "---> 点右边编辑查看示例效果", + status: "0", + remote2: "2", + editable: true + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/basis/first/index.vue b/packages/ui/certd-client/src/views/crud/basis/first/index.vue new file mode 100644 index 00000000..6edf3a6d --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/first/index.vue @@ -0,0 +1,109 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/basis/i18n/api.js b/packages/ui/certd-client/src/views/crud/basis/i18n/api.js new file mode 100644 index 00000000..d62b1b72 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/i18n/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/BasisI18n"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/basis/i18n/crud.jsx b/packages/ui/certd-client/src/views/crud/basis/i18n/crud.jsx new file mode 100644 index 00000000..e789ca3e --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/i18n/crud.jsx @@ -0,0 +1,72 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +import { useI18n } from "vue-i18n"; +export default function ({ expose }) { + const { t } = useI18n(); + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + name: { + title: t("app.crud.i18n.name"), + type: "text", + search: { show: true } + }, + city: { + title: t("app.crud.i18n.city"), + type: "dict-select", + search: { show: true }, + dict: dict({ + value: "id", + label: "text", + data: [ + { id: "sz", text: "深圳", color: "success" }, + { id: "gz", text: "广州", color: "blue" }, + { id: "bj", text: "北京" }, + { id: "wh", text: "武汉" }, + { id: "sh", text: "上海" } + ] + }) + }, + radio: { + title: t("app.crud.i18n.status"), + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/basis/i18n/index.vue b/packages/ui/certd-client/src/views/crud/basis/i18n/index.vue new file mode 100644 index 00000000..3c50ea0a --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/i18n/index.vue @@ -0,0 +1,53 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/basis/i18n/mock.js b/packages/ui/certd-client/src/views/crud/basis/i18n/mock.js new file mode 100644 index 00000000..4bbcc95b --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/i18n/mock.js @@ -0,0 +1,25 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "BasisI18n", + idGenerator: 0 +}; +const list = [ + { + radio: "1", + name: "张三", + city: "sz" + }, + { + radio: "2", + name: "李四", + city: "gz" + }, + { + radio: "0", + name: "王五", + city: "sh" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/basis/layout-card/api.js b/packages/ui/certd-client/src/views/crud/basis/layout-card/api.js new file mode 100644 index 00000000..1ee8f29f --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/layout-card/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/BasisLayoutCard"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/basis/layout-card/crud.jsx b/packages/ui/certd-client/src/views/crud/basis/layout-card/crud.jsx new file mode 100644 index 00000000..085f4852 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/layout-card/crud.jsx @@ -0,0 +1,73 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ crudExpose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + container: { + is: "fs-layout-card" + }, + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + name: { + title: "姓名", + type: "text", + search: { show: true } + }, + city: { + title: "城市", + type: "dict-select", + search: { show: true }, + dict: dict({ + value: "id", + label: "text", + data: [ + { id: "sz", text: "深圳", color: "success" }, + { id: "gz", text: "广州", color: "blue" }, + { id: "bj", text: "北京" }, + { id: "wh", text: "武汉" }, + { id: "sh", text: "上海" } + ] + }) + }, + radio: { + title: "单选", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/basis/layout-card/index.vue b/packages/ui/certd-client/src/views/crud/basis/layout-card/index.vue new file mode 100644 index 00000000..60597b7e --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/layout-card/index.vue @@ -0,0 +1,46 @@ + + + + + diff --git a/packages/ui/certd-client/src/views/crud/basis/layout-card/mock.js b/packages/ui/certd-client/src/views/crud/basis/layout-card/mock.js new file mode 100644 index 00000000..417d9601 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/layout-card/mock.js @@ -0,0 +1,25 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "BasisLayoutCard", + idGenerator: 0 +}; +const list = [ + { + radio: "1", + name: "张三", + city: "sz" + }, + { + radio: "2", + name: "李四", + city: "gz" + }, + { + radio: "0", + name: "王五", + city: "sh" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/basis/layout-custom/api.js b/packages/ui/certd-client/src/views/crud/basis/layout-custom/api.js new file mode 100644 index 00000000..f243b402 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/layout-custom/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/BasisLayoutCustom"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/basis/layout-custom/crud.jsx b/packages/ui/certd-client/src/views/crud/basis/layout-custom/crud.jsx new file mode 100644 index 00000000..85192994 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/layout-custom/crud.jsx @@ -0,0 +1,75 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +import CustomLayout from "./custom-layout.vue"; +import { shallowRef } from "vue"; +export default function ({ crudExpose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + container: { + is: shallowRef(CustomLayout) //可以将自定义布局组件全局注册,这里只需要配置name即可 + }, + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + name: { + title: "姓名", + type: "text", + search: { show: true } + }, + city: { + title: "城市", + type: "dict-select", + search: { show: false }, + dict: dict({ + value: "id", + label: "text", + data: [ + { id: "sz", text: "深圳", color: "success" }, + { id: "gz", text: "广州", color: "blue" }, + { id: "bj", text: "北京" }, + { id: "wh", text: "武汉" }, + { id: "sh", text: "上海" } + ] + }) + }, + radio: { + title: "单选", + search: { show: false }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/basis/layout-custom/custom-layout.vue b/packages/ui/certd-client/src/views/crud/basis/layout-custom/custom-layout.vue new file mode 100644 index 00000000..0f65a9b2 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/layout-custom/custom-layout.vue @@ -0,0 +1,74 @@ + + + + + diff --git a/packages/ui/certd-client/src/views/crud/basis/layout-custom/index.vue b/packages/ui/certd-client/src/views/crud/basis/layout-custom/index.vue new file mode 100644 index 00000000..747c9dd9 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/layout-custom/index.vue @@ -0,0 +1,56 @@ + + + + + diff --git a/packages/ui/certd-client/src/views/crud/basis/layout-custom/mock.js b/packages/ui/certd-client/src/views/crud/basis/layout-custom/mock.js new file mode 100644 index 00000000..d877b043 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/layout-custom/mock.js @@ -0,0 +1,25 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "BasisLayoutCustom", + idGenerator: 0 +}; +const list = [ + { + radio: "1", + name: "张三", + city: "sz" + }, + { + radio: "2", + name: "李四", + city: "gz" + }, + { + radio: "0", + name: "王五", + city: "sh" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/basis/value-change/api.js b/packages/ui/certd-client/src/views/crud/basis/value-change/api.js new file mode 100644 index 00000000..35fdfa0c --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/value-change/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/BasisValueChange"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/basis/value-change/crud.jsx b/packages/ui/certd-client/src/views/crud/basis/value-change/crud.jsx new file mode 100644 index 00000000..15dde4a4 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/value-change/crud.jsx @@ -0,0 +1,95 @@ +import * as api from "./api"; +import { message } from "ant-design-vue"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + return { + output: {}, + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + switch: { + title: "开关", + type: "dict-switch", + dict: dict({ + data: [ + { value: true, label: "开启" }, + { value: false, label: "关闭" } + ] + }), + column: { + component: { + name: "fs-dict-switch", + vModel: "checked" + }, + valueChange(context) { + console.log("column value changed:", context); + } + }, + form: { + valueChange({ value, key, form }) { + console.log("valueChanged,", key, value, form); + message.info(`valueChanged:${key}=${value}`); + } + } + }, + normal: { + title: "value-change", + type: "text", + form: { + valueChange({ value, key, form }) { + console.log("valueChanged,", key, value, form); + message.info(`valueChanged:${key}=${value}`); + } + } + }, + immediate: { + title: "immediate", + type: "text", + search: { + show: true + }, + form: { + valueChange: { + handle({ value, key, form, immediate }) { + console.log("valueChange,", key, value, "isImmediate=", immediate); + message.info(`valueChanged:${key}=${value},isImmediate=${immediate}`); + }, + immediate: true + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/basis/value-change/index.vue b/packages/ui/certd-client/src/views/crud/basis/value-change/index.vue new file mode 100644 index 00000000..0a6bc659 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/value-change/index.vue @@ -0,0 +1,43 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/basis/value-change/mock.js b/packages/ui/certd-client/src/views/crud/basis/value-change/mock.js new file mode 100644 index 00000000..2d16ebcc --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/basis/value-change/mock.js @@ -0,0 +1,32 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "BasisValueChange", + idGenerator: 0 +}; +const list = [ + { + ref: "根据showRef显示", + compute: true, + status: "1", + remote: "2", + shower: "---> 点右边编辑查看示例效果", + remote2: "2", + editable: true + }, + { + compute: false, + status: "2", + remote: "0", + remote2: "2", + editable: false + }, + { + compute: true, + status: "0", + remote2: "2", + editable: true + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/component/button/api.js b/packages/ui/certd-client/src/views/crud/component/button/api.js new file mode 100644 index 00000000..99ab67a8 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/button/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/ComponentButton"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/component/button/crud.jsx b/packages/ui/certd-client/src/views/crud/component/button/crud.jsx new file mode 100644 index 00000000..4e10ee19 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/button/crud.jsx @@ -0,0 +1,115 @@ +import * as api from "./api"; +import { requestForMock } from "/src/api/service"; +import { dict, compute } from "@fast-crud/fast-crud"; +import { message } from "ant-design-vue"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + form: { + //配置表单label的宽度 + labelCol: { span: 6 } + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + button: { + title: "按钮", + search: { show: true }, + type: "button", + column: { + component: { + show: compute(({ value }) => { + //当value为null时,不显示 + return value != null; + }), + on: { + // 注意:必须要on前缀 + onClick({ row }) { + message.success("按钮点击:" + row.button); + } + } + } + } + }, + url: { + title: "url", + search: { show: true }, + type: "text", + column: { + show: false + } + }, + link: { + title: "链接", + search: { show: true }, + type: "link", + column: { + component: { + on: { + // 注意:必须要on前缀 + onClick({ row }) { + if (row.url) { + window.open(row.url); + } + } + } + } + }, + form: { + title: "按钮文字" + } + }, + link2: { + title: "手写link配置", + search: { show: true }, + type: "text", //form组件用input + column: { + component: { + name: "fs-button", //列展示组件为button + vModel: "text", // 将row.link2的值赋值给text属性 + type: "link", // 按钮展示为链接样式 + on: { + //注册点击事件 + // 注意:必须要on前缀 + onClick({ row }) { + if (row.url) { + window.open(row.url); + } + } + } + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/component/button/index.vue b/packages/ui/certd-client/src/views/crud/component/button/index.vue new file mode 100644 index 00000000..bf86cd95 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/button/index.vue @@ -0,0 +1,42 @@ + + + + + diff --git a/packages/ui/certd-client/src/views/crud/component/button/mock.js b/packages/ui/certd-client/src/views/crud/component/button/mock.js new file mode 100644 index 00000000..bddcce22 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/button/mock.js @@ -0,0 +1,23 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "ComponentButton", + idGenerator: 0 +}; +const list = [ + { + button: "张三", + link: "百度", + url: "https://www.baidu.com", + link2: "手写配置" + }, + { + button: "李四", + link: "百度", + url: "https://www.baidu.com", + link2: "手写配置" + }, + {} +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/component/cascader/api.js b/packages/ui/certd-client/src/views/crud/component/cascader/api.js new file mode 100644 index 00000000..8e851ae5 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/cascader/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/ComponentCascader"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/component/cascader/crud.jsx b/packages/ui/certd-client/src/views/crud/component/cascader/crud.jsx new file mode 100644 index 00000000..2b5206b7 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/cascader/crud.jsx @@ -0,0 +1,137 @@ +import * as api from "./api"; +import { requestForMock } from "/src/api/service"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ crudRef }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + form: { + // 单列布局 + col: { span: 24 }, + labelCol: { span: 4 }, + wrapperCol: { span: 18 } + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + cascader: { + title: "级联", + search: { show: true }, + type: "dict-cascader", + dict: dict({ + cloneable: false, + isTree: true, + url: "/mock/dicts/cascaderData?single" + }) + }, + lazyLoad: { + title: "懒加载", + type: "dict-cascader", + dict: dict({ + url: "/mock/tree/GetTreeChildrenByParentId?lazyLoad", + value: "code", + label: "name", + isTree: true, + prototype: true, + getNodesByValues(values) { + //给cell展示组件调用,根据value值获取节点,每行都会请求一次 + if (values == null) { + return []; + } + return requestForMock({ + url: "/mock/tree/GetNodesByValues", + params: { values } + }); + } + }), + form: { + component: { + vModel: "value", + options: [ + { + code: "11", + name: "北京", + isLeaf: false + }, + { + code: "12", + name: "天津", + isLeaf: false + } + ], + loadData: async (selectedOptions) => { + console.log("lazyLoad", selectedOptions); + const targetOption = selectedOptions[selectedOptions.length - 1]; + targetOption.loading = true; + + const ret = await requestForMock({ + url: "/mock/tree/GetTreeChildrenByParentId", + params: { parentId: targetOption.code } + }); + targetOption.loading = false; + const list = []; + for (const item of ret) { + list.push({ + code: item.code, + name: item.name, + isLeaf: item.leaf === true + }); + } + targetOption.children = list; + //options.value = [...options.value]; + }, + changeOnSelect: true + } + } + }, + multiple: { + title: "可搜索,可只选父节点", + type: "dict-cascader", + dict: dict({ + isTree: true, + url: "/mock/dicts/cascaderData?multiple" + }), + form: { + component: { + showSearch: { + filter: (inputValue, path) => { + return path.some((option) => option.label.toLowerCase().indexOf(inputValue.toLowerCase()) > -1); + } + }, + "change-on-select": true + }, + helper: "antd cascader 不支持级联多选" + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/component/cascader/index.vue b/packages/ui/certd-client/src/views/crud/component/cascader/index.vue new file mode 100644 index 00000000..58428ac7 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/cascader/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/component/cascader/mock.js b/packages/ui/certd-client/src/views/crud/component/cascader/mock.js new file mode 100644 index 00000000..01bc0582 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/cascader/mock.js @@ -0,0 +1,23 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "ComponentCascader", + idGenerator: 0 +}; +const list = [ + { + cascader: ["zhinan", "shejiyuanze", "yizhi"], + lazyLoad: ["11", "1101", "110101", "110101001"], + multiple: ["antdv cascader不支持多选"] + }, + { + cascader: ["zhinan", "shejiyuanze", "yizhi"], + multiple: ["antdv cascader不支持多选"] + }, + { + cascader: ["zhinan", "shejiyuanze", "yizhi"], + multiple: ["antdv cascader不支持多选"] + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/component/checkbox/api.js b/packages/ui/certd-client/src/views/crud/component/checkbox/api.js new file mode 100644 index 00000000..f1d4edba --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/checkbox/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/ComponentCheckbox"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/component/checkbox/crud.jsx b/packages/ui/certd-client/src/views/crud/component/checkbox/crud.jsx new file mode 100644 index 00000000..ba55af1b --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/checkbox/crud.jsx @@ -0,0 +1,50 @@ +import * as api from "./api"; +import { requestForMock } from "/src/api/service"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ crudRef }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + checkbox: { + title: "状态", + search: { show: true }, + type: "dict-checkbox", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/component/checkbox/index.vue b/packages/ui/certd-client/src/views/crud/component/checkbox/index.vue new file mode 100644 index 00000000..a1dd4729 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/checkbox/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/component/checkbox/mock.js b/packages/ui/certd-client/src/views/crud/component/checkbox/mock.js new file mode 100644 index 00000000..1763e9bb --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/checkbox/mock.js @@ -0,0 +1,19 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "ComponentCheckbox", + idGenerator: 0 +}; +const list = [ + { + checkbox: ["1", "2"] + }, + { + checkbox: "2" + }, + { + checkbox: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/component/date/api.js b/packages/ui/certd-client/src/views/crud/component/date/api.js new file mode 100644 index 00000000..f6a0197f --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/date/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/ComponentDate"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/component/date/crud.jsx b/packages/ui/certd-client/src/views/crud/component/date/crud.jsx new file mode 100644 index 00000000..ba405c56 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/date/crud.jsx @@ -0,0 +1,174 @@ +import * as api from "./api"; +import { utils } from "@fast-crud/fast-crud"; +import dayjs from "dayjs"; + +console.log("utils", utils); +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + table: { + scroll: { x: 2000 } + }, + rowHandle: { fixed: "right" }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + timestamp: { + title: "时间戳", + type: "datetime", + search: { + show: true, + width: 185, + component: {} + }, + valueBuilder({ value, row, key }) { + console.log("value builder:", key, value, row); + if (value != null) { + row[key] = dayjs(value); + } + }, + valueResolve({ value, row, key }) { + if (value != null) { + row[key] = value.unix(); + } + } + }, + humanize: { + type: ["datetime", "time-humanize"], + title: "人性化时间", + column: { + component: { + options: { + largest: 2 + } + } + } + }, + datetime: { + title: "日期时间", + type: "datetime", + form: { + component: { + valueFormat: "YYYY-MM-DD HH:mm:ss" //输入值的格式 + } + } + }, + format: { + title: "格式化", + type: "datetime", + form: { + component: { + format: "YYYY年MM月DD日 HH:mm", + valueFormat: "YYYY-MM-DD HH:mm:ss" //输入值的格式 + } + }, + column: { + width: 180, + component: { + // 行展示组件使用的dayjs, + format: "YYYY年MM月DD日 HH:mm" + } + } + }, + date: { + title: "仅日期", + type: "date", + form: { + component: { + valueFormat: "YYYY-MM-DD HH:mm:ss", //输入值的格式 + events: { + onChange(context) { + console.log("change", context); + } + } + } + } + }, + time: { + title: "仅时间", + type: "time", + form: { + component: { + valueFormat: "YYYY-MM-DD HH:mm:ss" //输入值的格式 + } + } + }, + disabledDate: { + title: "禁用日期", + type: "date", + form: { + component: { + valueFormat: "YYYY-MM-DD HH:mm:ss", //输入值的格式 + disabledDate(current) { + return current && current < dayjs().endOf("day"); + } + } + } + }, + daterange: { + title: "日期范围", + type: "daterange", + search: { show: true, width: 300 }, + valueBuilder({ row, key }) { + if (!utils.strings.hasEmpty(row.daterangeStart, row.daterangeEnd)) { + row[key] = [dayjs(row.daterangeStart), dayjs(row.daterangeEnd)]; + } + } + }, + datetimerange: { + title: "日期时间范围", + type: "datetimerange", + search: { show: true, width: 300 }, + valueBuilder({ row, key }) { + if (!utils.strings.hasEmpty(row.datetimerangeStart, row.datetimerangeEnd)) { + row[key] = [dayjs(row.datetimerangeStart), dayjs(row.datetimerangeEnd)]; + } + }, + valueResolve({ form, key }) { + const row = form; + if (row[key] != null && !utils.strings.hasEmpty(row[key])) { + row.datetimerangeStart = row[key][0]; + row.datetimerangeEnd = row[key][1]; + } else { + row.datetimerangeStart = null; + row.datetimerangeEnd = null; + } + } + }, + customType: { + title: "自定义字段类型", + type: "time2" + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/component/date/index.vue b/packages/ui/certd-client/src/views/crud/component/date/index.vue new file mode 100644 index 00000000..8ec79528 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/date/index.vue @@ -0,0 +1,47 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/component/date/mock.js b/packages/ui/certd-client/src/views/crud/component/date/mock.js new file mode 100644 index 00000000..895fddda --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/date/mock.js @@ -0,0 +1,44 @@ +import mockUtil from "/src/mock/base"; + +const options = { + name: "ComponentDate", + idGenerator: 0 +}; +const list = [ + { + timestamp: 123123123123, + humanize: new Date().getTime() - 11111111, + datetime: "2019-09-01 11:11:11", + date: "2019-09-02 11:11:11", + format: "2019-09-21 11:11:11", + time: "2019-09-22 12:11:11", + daterangeStart: "2019-09-23 11:11:11", + daterangeEnd: "2019-09-24 11:11:11", + datetimerangeStart: "2019-09-25 11:11:11", + datetimerangeEnd: "2019-09-26 11:11:11" + }, + { + // timestamp: 444444555, + datetime: "2017-09-20 11:11:11", + date: "2019-09-20 11:11:11", + humanize: new Date().getTime() - 22222222, + // time: 12313123334, + daterangeStart: "2019-09-20 11:11:11", + daterangeEnd: "2019-09-21 11:11:11", + datetimerangeStart: "2019-09-20 11:11:11", + datetimerangeEnd: "2019-09-21 11:11:11" + }, + { + // timestamp: 5555555555, + datetime: "2017-09-20 11:11:11", + date: "2019-09-20 11:11:11", + // time: 12313123334, + daterangeStart: "2019-09-20 11:11:11", + daterangeEnd: "2019-09-21 11:11:11", + datetimerangeStart: "2019-09-20 11:11:11", + datetimerangeEnd: "2019-09-21 11:11:11" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/component/editor/api.js b/packages/ui/certd-client/src/views/crud/component/editor/api.js new file mode 100644 index 00000000..523cfb37 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/editor/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/ComponentEditor"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/component/editor/crud.jsx b/packages/ui/certd-client/src/views/crud/component/editor/crud.jsx new file mode 100644 index 00000000..d32431b7 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/editor/crud.jsx @@ -0,0 +1,107 @@ +import * as api from "./api"; +import { utils, dict, compute } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + title: { + title: "标题", + type: "text", + column: { + width: 400 + }, + form:{ + col: { span: 24 }, + }, + }, + text: { + title: "摘要", + type: "textarea", + form:{ + col: { span: 24 }, + }, + viewForm: { + component: { + name: null, + render(h, scope) { + return
{scope.value}
; + } + } + } + }, + disabled: { + title: "禁用启用", + search: { show: false }, + type: "dict-switch", + dict: dict({ + data: [ + { value: true, label: "禁用" }, + { value: false, label: "启用" } + ] + }) + }, + content_wang: { + title: "内容", + column: { + width: 300, + show: false + }, + type: ["editor-wang5"], // 富文本图片上传依赖file-uploader,请先配置好file-uploader + form: { + helper:"示例已升级到wangEditor5版本,原来的editor-wang目前仍然可以使用,后续fs升级可能会将其删除,请尽快升级到editor-wang5版本", + col: { span: 24 }, + // 动态显隐字段 + // show: compute(({ form }) => { + // return form.change === "wang"; + // }), + rules: [{ required: true, message: "此项必填" }], + component: { + disabled: compute(({ form }) => { + return form.disabled; + }), + id: "1", // 当同一个页面有多个editor时,需要配置不同的id + config: {}, + uploader: { + type: "form", + buildUrl(res) { + return res.url; + } + } + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/component/editor/index.vue b/packages/ui/certd-client/src/views/crud/component/editor/index.vue new file mode 100644 index 00000000..61e5e203 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/editor/index.vue @@ -0,0 +1,44 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/component/editor/mock.js b/packages/ui/certd-client/src/views/crud/component/editor/mock.js new file mode 100644 index 00000000..8351e075 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/editor/mock.js @@ -0,0 +1,29 @@ +import mockUtil from "/src/mock/base"; + +const options = { + name: "ComponentEditor", + idGenerator: 0 +}; +const list = [ + { + title: "d2-crud-plus好用吗?", + text: "非常好用", + content_quill: '

非常好用哦

', + change: "quill" + }, + { + title: "d2-crud-plus有什么优势?", + text: "简单,方便", + content_quill: "简单方便", + change: "wang" + }, + { + title: "1111111", + text: "22222", + content_quill: "3333", + change: "wang" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/component/icon/api.js b/packages/ui/certd-client/src/views/crud/component/icon/api.js new file mode 100644 index 00000000..4db9ed9b --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/icon/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/ComponentIcon"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/component/icon/crud.jsx b/packages/ui/certd-client/src/views/crud/component/icon/crud.jsx new file mode 100644 index 00000000..ad9c38be --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/icon/crud.jsx @@ -0,0 +1,75 @@ +import * as api from "./api"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + icon: { + title: "icon", + search: { show: true }, + type: "text", + column: { + component: { + name: "fs-icon", + vModel: "icon", + style: "font-size:18px" + } + }, + form: { + helper: { + render() { + return ( + + 点击此处选择图标名称 + + ); + } + } + } + }, + svg: { + title: "svg", + search: { show: true }, + type: "text", + column: { + component: { + name: "fs-icon", + vModel: "icon", + style: "font-size:18px" + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/component/icon/index.vue b/packages/ui/certd-client/src/views/crud/component/icon/index.vue new file mode 100644 index 00000000..f8f1e929 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/icon/index.vue @@ -0,0 +1,42 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/component/icon/mock.js b/packages/ui/certd-client/src/views/crud/component/icon/mock.js new file mode 100644 index 00000000..fe2de8ed --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/icon/mock.js @@ -0,0 +1,22 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "ComponentIcon", + idGenerator: 0 +}; +const list = [ + { + icon: "ri:24-hours-fill", + svg:"svg:icon-compass" + }, + { + icon: "ion:add-circle-outline", + svg:"svg:icon-left-circle" + }, + { + icon: "ion:american-football-sharp", + svg:"svg:icon-Dollar" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/component/json/api.js b/packages/ui/certd-client/src/views/crud/component/json/api.js new file mode 100644 index 00000000..a62736e6 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/json/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/ComponentJson"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/component/json/crud.jsx b/packages/ui/certd-client/src/views/crud/component/json/crud.jsx new file mode 100644 index 00000000..898fb5d3 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/json/crud.jsx @@ -0,0 +1,78 @@ +import * as api from "./api"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + form: { + wrapper: { + async onOpened({ mode, formRef }) { + if (!formRef.form.async) { + setTimeout(() => { + formRef.form.async = { aaa: "11", bb: "111" }; + }, 2000); + } + } + } + }, + columns: { + json: { + title: "json", + type: "json", + form: { + valueBuilder({ form }) { + if (form.json == null) { + return; + } + form.json = JSON.parse(form.json); + }, + valueResolve({ form }) { + if (form.json == null) { + return; + } + form.json = JSON.stringify(form.json); + } + } + }, + async: { + title: "异步加载", + type: "json", + form: { + // 上面form.wrapper.onOpened里面配置了异步加载 + helper: "在onOpened里面配置异步加载json字符串", + valueBuilder({ form }) { + if (form.async == null) { + return; + } + form.async = JSON.parse(form.async); + }, + valueResolve({ form }) { + if (form.async == null) { + return; + } + form.async = JSON.stringify(form.async); + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/component/json/index.vue b/packages/ui/certd-client/src/views/crud/component/json/index.vue new file mode 100644 index 00000000..34868881 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/json/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/component/json/mock.js b/packages/ui/certd-client/src/views/crud/component/json/mock.js new file mode 100644 index 00000000..727a1788 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/json/mock.js @@ -0,0 +1,18 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "ComponentJson", + idGenerator: 0 +}; +const list = [ + { + json: '{"a":1,"b":2}', + async: null + }, + { + json: '{"a":3,"b":4}', + async: null + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/component/number/api.js b/packages/ui/certd-client/src/views/crud/component/number/api.js new file mode 100644 index 00000000..30c88fc3 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/number/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/ComponentNumber"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/component/number/crud.jsx b/packages/ui/certd-client/src/views/crud/component/number/crud.jsx new file mode 100644 index 00000000..057f7b18 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/number/crud.jsx @@ -0,0 +1,71 @@ +import * as api from "./api"; +import { requestForMock } from "/src/api/service"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + integer: { + title: "整数", + search: { show: true }, + type: "number" + }, + float: { + title: "小数", + type: "number", + form: { + component: { + step: "0.1" + } + } + }, + format: { + title: "格式化", + type: "number", + form: { + component: { + formatter: (value) => `${value}%`, + parser: (value) => value.replace("%", "") + } + }, + column: { + formatter({ value }) { + return value + "%"; + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/component/number/index.vue b/packages/ui/certd-client/src/views/crud/component/number/index.vue new file mode 100644 index 00000000..f6989e02 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/number/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/component/number/mock.js b/packages/ui/certd-client/src/views/crud/component/number/mock.js new file mode 100644 index 00000000..6b8854a1 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/number/mock.js @@ -0,0 +1,25 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "ComponentNumber", + idGenerator: 0 +}; +const list = [ + { + integer: 1, + float: 1.1, + format: 100 + }, + { + integer: 2, + float: 1.2, + format: 100 + }, + { + integer: 3, + float: 1.3, + format: 100 + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/component/radio/api.js b/packages/ui/certd-client/src/views/crud/component/radio/api.js new file mode 100644 index 00000000..761dae47 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/radio/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/ComponentRadio"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/component/radio/crud.jsx b/packages/ui/certd-client/src/views/crud/component/radio/crud.jsx new file mode 100644 index 00000000..cf732019 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/radio/crud.jsx @@ -0,0 +1,73 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + }, + button: { + title: "按钮样式", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }), + form: { + component: { + optionName: "a-radio-button" + } + } + }, + bool: { + title: "布尔类型", + search: { show: true }, + type: "dict-radio", + dict: dict({ + data: [ + { value: true, label: "TRUE" }, + { value: false, label: "FALSE" } + ] + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/component/radio/index.vue b/packages/ui/certd-client/src/views/crud/component/radio/index.vue new file mode 100644 index 00000000..d851e585 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/radio/index.vue @@ -0,0 +1,42 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/component/radio/mock.js b/packages/ui/certd-client/src/views/crud/component/radio/mock.js new file mode 100644 index 00000000..64751485 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/radio/mock.js @@ -0,0 +1,24 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "ComponentRadio", + idGenerator: 0 +}; +const list = [ + { + radio: "1", + button: "1", + bool: true + }, + { + radio: "2", + button: "2", + bool: false + }, + { + radio: "0", + button: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/component/select/api.js b/packages/ui/certd-client/src/views/crud/component/select/api.js new file mode 100644 index 00000000..6c9e2511 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/select/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/ComponentSelect"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/component/select/crud.jsx b/packages/ui/certd-client/src/views/crud/component/select/crud.jsx new file mode 100644 index 00000000..a04fafa0 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/select/crud.jsx @@ -0,0 +1,311 @@ +import * as api from "./api"; +import { requestForMock } from "/src/api/service"; +import { dict } from "@fast-crud/fast-crud"; +import { ref } from "vue"; +import _ from "lodash-es"; +function useSearchRemote() { + let lastFetchId = 0; + + const state = { + data: ref([]), + fetching: ref(false) + }; + const fetchUser = _.debounce((value) => { + console.log("fetching user", value); + lastFetchId += 1; + + const fetchId = lastFetchId; + + state.data.value = []; + + state.fetching.value = true; + + fetch("https://randomuser.me/api/?results=5") + .then((response) => response.json()) + .then((body) => { + if (fetchId !== lastFetchId) { + // for fetch callback order + return; + } + const data = body.results.map((user) => ({ + text: `${user.name.first} ${user.name.last}`, + value: user.login.username + })); + state.data.value = data; + state.fetching.value = false; + }); + }, 800); + + return { + fetchUser, + searchState: state + }; +} +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + const dictRef = dict({ + value: "id", + label: "text", + data: [ + { id: "sz", text: "深圳", color: "success" }, + { id: "gz", text: "广州", color: "blue" }, + { id: "bj", text: "北京" }, + { id: "wh", text: "武汉" }, + { id: "sh", text: "上海" } + ] + }); + + function dynamicUpdateDictOptions() { + dictRef.data.push({ id: "xg", text: "香港" }); + //dictRef.toMap(); + } + + const { fetchUser, searchState } = useSearchRemote(); + return { + dynamicUpdateDictOptions, + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + form: { + // 单列布局 + col: { span: 24 }, + labelCol: { span: 4 }, + wrapperCol: { span: 18 } + }, + rowHandle: { + fixed: "right", + align: "center" + }, + table: { + scroll: { + //启用横向滚动条,设置一个大于所有列宽之和的值,一般大于表格宽度 + x: 1400 + } + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + statusLocal: { + title: "单选本地", + type: "dict-select", + dict: dictRef + }, + statusRemote: { + title: "单选远程", + search: { + show: true, + rules: null, + component: { + style: { width: "100px" } + } + }, + type: "dict-select", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?simple" + }), + form: { + rules: [{ required: true, message: "请选择一个选项" }] + } + }, + filter: { + title: "本地过滤", + type: "dict-select", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?simple" + }), + form: { + component: { + showSearch: true, + //默认的filterOption仅支持value的过滤,label并不会加入查询 + //所以需要自定义filterOption + filterOption(inputValue, option) { + return option.label.indexOf(inputValue) >= 0 || option.value.indexOf(inputValue) >= 0; + } + } + } + }, + search: { + title: "远程搜索", + search: { show: true, component: { style: { width: "240px" } } }, + form: { + component: { + name: "a-select", + vModel: "value", + filterOption: false, + //labelInValue: true, + mode: "multiple", + showSearch: true, + allowClear: true, + placeholder: "输入远程搜索,数据仅供演示", + options: searchState.data, + onSearch(value) { + fetchUser(value); + }, + children: { + notFoundContent() { + if (searchState.fetching.value) { + return ; + } + return "暂无记录"; + } + } + } + } + }, + customDictGetData: { + title: "自定义字典请求", + search: { show: false }, + type: "dict-select", + dict: dict({ + getData({ dict }) { + // 覆盖全局获取字典请求配置 + console.log(`我是从自定义的getData方法中加载的数据字典`, dict); + return requestForMock({ + url: "/mock/dicts/OpenStatusEnum?cache", + method: "get" + }); + } + }), + form: { + value: "2", //默认值, 注意search也会影响到,需要将search.value=null,取消search的默认值 + helper: "dict.getData可以覆盖全局配置的getRemoteDictFunc" + }, + column: { + width: 120, + component: { + type: "text" // 不使用tag,纯文本展示 + } + } + }, + disabledOptions: { + title: "禁用某个选项", + key: "disabledOptions", + type: "dict-select", + dict: dict({ + cloneable: true, + url: "/mock/dicts/OpenStatusEnum?disabledOptions" + }), + form: { + component: { + dict: { + // 此处dict配置会覆盖上面dict的属性 + prototype: true, // form表单的dict设置为原型复制,每次初始化时都会重新loadDict + onReady({ dict }) { + console.log("字典请求ready", dict); + dict.data[0].disabled = true; // 禁用某个选项, 还可以自己修改选项 + } + } + }, + helper: "禁用字典选项" + }, + column: { + width: 150 + } + }, + firstDefault: { + title: "默认值", + type: "dict-select", + dict: dict({ + cloneable: true, + url: "/mock/dicts/OpenStatusEnum?disabledOptions" + }), + form: { + component: { + //监听 dict-change事件 + onDictChange({ dict, form, key }) { + console.log("dict data changed", dict, key); + if (dict.data != null && form.firstDefault == null) { + form.firstDefault = dict.data[0].value; + } + } + // 下面的方法也可以,注意要配置dict.prototype:true + // dict: { + // // 此处dict配置会覆盖上面dict的属性 + // // form表单的dict设置为原型复制,每次初始化时都会重新loadDict + // prototype: true, + // + // onReady({ dict, form }) { + // console.log("字典请求ready", dict, form, getComponentRef); + // // prototype= true 才能获取到form表单数据 + // form.firstDefault = dict.data[0].value; + // } + // } + }, + helper: "默认选择第一个选项" + } + }, + multiple: { + title: "多选自动染色", + sortable: true, + type: "dict-select", + form: { + title: "多选本地", + component: { + mode: "multiple" + } + }, + dict: dict({ + data: [ + { value: "sz", label: "深圳", color: "success" }, + { value: "gz", label: "广州" }, + { value: "wh", label: "武汉" }, + { value: "sh", label: "上海" }, + { value: "hz", label: "杭州" }, + { value: "bj", label: "北京", color: "red" } + ] + }), + column: { + width: 290, + component: { + color: "auto", // 自动染色 + defaultLabel: "未知城市" //无数据字典时的默认文本 + } + } + }, + statusSimple: { + title: "普通选择", + form: { + component: { + name: "a-select", + vModel: "value", + options: [ + { value: "sz", label: "深圳", color: "success" }, + { value: "gz", label: "广州", color: "blue" }, + { value: "bj", label: "北京" }, + { value: "wh", label: "武汉" }, + { value: "sh", label: "上海" } + ] + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/component/select/index.vue b/packages/ui/certd-client/src/views/crud/component/select/index.vue new file mode 100644 index 00000000..8278b456 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/select/index.vue @@ -0,0 +1,45 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/component/select/mock.js b/packages/ui/certd-client/src/views/crud/component/select/mock.js new file mode 100644 index 00000000..d7448877 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/select/mock.js @@ -0,0 +1,42 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "ComponentSelect", + idGenerator: 0 +}; +const list = [ + { + statusLocal: "sz", + customDictUrl: "0", + statusValue: 1, + multiple: ["sz", "bj", "gz", "sh", "hz", "xz", "xg"], + checkbox: "0", + select_local: "sz", + statusRemote: "0", + status_custom_2: "0", + customDictGetData: "1", + checkbox_btn: "1" + }, + { + statusLocal: "xg", + customDictUrl: "1", + statusValue: 2, + statusRemote: "1", + status_custom_2: "2", + select_local: "gz", + multiple: ["sh", "sz"], + checkbox: "0" + }, + { + statusLocal: "gz", + customDictUrl: "1", + statusValue: 1, + disabledCache: "1", + disabledOptions: "2", + select_local: "gz", + multiple: ["sh", "gz"], + checkbox: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/component/switch/api.js b/packages/ui/certd-client/src/views/crud/component/switch/api.js new file mode 100644 index 00000000..f2e25bed --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/switch/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/ComponentSwitch"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/component/switch/crud.jsx b/packages/ui/certd-client/src/views/crud/component/switch/crud.jsx new file mode 100644 index 00000000..e2d751a7 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/switch/crud.jsx @@ -0,0 +1,141 @@ +import * as api from "./api"; +import { dict, compute } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + switch: { + title: "状态", + search: { show: true }, + type: "dict-switch", + dict: dict({ + data: [ + { value: false, label: "开启" }, + { value: true, label: "关闭" } + ] + }) + }, + notBool: { + title: "自定义value", + search: { show: true }, + type: "dict-switch", + dict: dict({ + data: [ + { value: "1", label: "开启" }, + { value: "2", label: "关闭" } + ] + }) + }, + switchLabel: { + title: "切换字段label", + search: { show: true }, + type: "dict-switch", + dict: dict({ + data: [ + { value: true, label: "开启" }, + { value: false, label: "关闭" } + ] + }), + column: { + show: false + } + }, + labelTarget: { + title: "我将被切换", + type: "text", + column: { + show: false + }, + form: { + label: compute(({ form }) => { + return form.switchLabel ? "我将被切换" : "再切换一下"; + }) + } + }, + cellSwitch: { + title: "cell显示", + search: { show: true }, + type: "dict-switch", + form: { + component: {} + }, + column: { + component: { + name: "fs-dict-switch", + vModel: "checked", + onChange: (value) => { + console.log("onChange", value); + } + // onChange: compute((context) => { + // //动态onChange方法测试 + // return () => { + // console.log("onChange", context.row.cellSwitch); + // }; + // }) + } + }, + dict: dict({ + data: [ + { value: true, label: "开启" }, + { value: false, label: "关闭" } + ] + }) + }, + showTarget: { + title: "显隐目标", + type: "text", + column: { + component: { + name: "fs-values-format", + show: compute((context) => { + //根据cellSwitch字段显隐 + return context.row.cellSwitch === true; + }) + } + }, + search: { + show: false + }, + form: { + show: compute((context) => { + console.log("context", context); + //根据cellSwitch字段显隐 + return context.form.cellSwitch === true; + }) + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/component/switch/index.vue b/packages/ui/certd-client/src/views/crud/component/switch/index.vue new file mode 100644 index 00000000..beb30f7d --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/switch/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/component/switch/mock.js b/packages/ui/certd-client/src/views/crud/component/switch/mock.js new file mode 100644 index 00000000..42772b1f --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/switch/mock.js @@ -0,0 +1,27 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "ComponentSwitch", + idGenerator: 0 +}; +const list = [ + { + switch: true, + cellSwitch: true, + notBool: "1", + showTarget: "点左边开关显示或隐藏" + }, + { + switch: false, + cellSwitch: true, + notBool: "2", + showTarget: "点左边开关显示或隐藏" + }, + { + switch: true, + cellSwitch: false, + showTarget: "点左边开关显示或隐藏" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/component/text/api.js b/packages/ui/certd-client/src/views/crud/component/text/api.js new file mode 100644 index 00000000..2111f772 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/text/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/ComponentText"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/component/text/crud.jsx b/packages/ui/certd-client/src/views/crud/component/text/crud.jsx new file mode 100644 index 00000000..24850e9e --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/text/crud.jsx @@ -0,0 +1,130 @@ +import * as api from "./api"; +import { compute } from "@fast-crud/fast-crud"; +import { resolveDirective, withDirectives } from "vue"; + +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + name: { + title: "姓名", + type: "text", //虽然不写也能正确显示组件,但不建议省略它 + search: { show: true }, + form: { + component: { + maxlength: 20 + } + } + }, + search: { + title: "搜索", + type: "text", + form: { + component: { + addonAfter: "后置", + suffix: "suffix", + children: { + addonBefore() { + return ; + } + } + } + } + }, + password: { + title: "密码", + type: "password", + column: { + //一般密码不显示在列里面 + show: false + } + }, + // copy: { + // title: "剪贴板", + // type: "text", + // column: { + // cellRender({ value, row }) { + // const content = ( + //
+ // {value} + // 复制 + //
+ // ); + // const clipboard = resolveDirective("clipboard"); + // return withDirectives(content, [[clipboard, value]]); + // } + // } + // }, + copy: { + title: "剪贴板", + type: ["text", "copyable"] + }, + intro: { + title: "简介", + type: "textarea", + form: { + component: { showWordLimit: true, maxlength: 200 } + }, + column: { + ellipsis: true, + showTitle: true + } + }, + render: { + title: "复杂输入(render)", + form: { + title: "复杂输入", + component: { + render(context) { + console.log("context scope", context); + return ( + + + + + ); + } + } + } + }, + render2: { + title: "我的值是由复杂输入列输入的", + column: { + width: "300px" + }, + form: { + show: false + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/component/text/index.vue b/packages/ui/certd-client/src/views/crud/component/text/index.vue new file mode 100644 index 00000000..a97ef551 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/text/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/component/text/mock.js b/packages/ui/certd-client/src/views/crud/component/text/mock.js new file mode 100644 index 00000000..4bc9df77 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/text/mock.js @@ -0,0 +1,43 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "ComponentText", + idGenerator: 0 +}; +const list = [ + { + name: "王小虎", + date: "2016-05-02", + status: "0", + province: "1", + avatar: "https://alicdn.antdv.com/vue.png", + show: true, + city: "sz", + address: "123123", + zip: "518000", + intro: "王小虎是element-plus的table示例出现的名字", + copy: "测试文本" + }, + { + name: "张三", + date: "2016-05-04", + status: "1", + province: "2", + copy: "测试文本" + }, + { + name: "李四", + date: 2232433534511, + status: "1", + province: "0", + copy: "测试文本" + }, + { + name: "王五", + date: "2016-05-03", + status: "2", + province: "wh,gz" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/component/tree/api.js b/packages/ui/certd-client/src/views/crud/component/tree/api.js new file mode 100644 index 00000000..b9db03f1 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/tree/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/ComponentTree"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/component/tree/crud.jsx b/packages/ui/certd-client/src/views/crud/component/tree/crud.jsx new file mode 100644 index 00000000..1d3ce5ab --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/tree/crud.jsx @@ -0,0 +1,81 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + tree: { + title: "树形选择", + search: { show: false }, + type: "dict-tree", + dict: dict({ + isTree: true, + url: "/mock/dicts/cascaderData?single" + }) + }, + multiple: { + title: "多选", + search: { show: false }, + type: "dict-tree", + dict: dict({ + cloneable: false, + isTree: true, + url: "/mock/dicts/cascaderData?single" + }), + form: { + component: { + "tree-checkable": true + } + } + }, + fieldReplace: { + title: "修改options的value字段名", + search: { show: false }, + type: "dict-tree", + dict: dict({ + isTree: true, + url: "/mock/dicts/littlePca", + value: "code", + label: "name" + }), + form: { + component: { + fieldNames: { label: "name", key: "code", value: "code" } + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/component/tree/index.vue b/packages/ui/certd-client/src/views/crud/component/tree/index.vue new file mode 100644 index 00000000..b5c74073 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/tree/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/component/tree/mock.js b/packages/ui/certd-client/src/views/crud/component/tree/mock.js new file mode 100644 index 00000000..ed3a1d39 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/tree/mock.js @@ -0,0 +1,16 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "ComponentTree", + idGenerator: 0 +}; +const list = [ + { + tree: "zhinan", + multiple: ["zhinan", "yizhi"] + }, + { tree: "zhinan" }, + { tree: "zhinan" } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/component/uploader/alioss/api.js b/packages/ui/certd-client/src/views/crud/component/uploader/alioss/api.js new file mode 100644 index 00000000..c5871d5b --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/uploader/alioss/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/AliossUploader"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/component/uploader/alioss/crud.jsx b/packages/ui/certd-client/src/views/crud/component/uploader/alioss/crud.jsx new file mode 100644 index 00000000..c5dd0c41 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/uploader/alioss/crud.jsx @@ -0,0 +1,75 @@ +import * as api from "./api"; +import { requestForMock } from "/src/api/service"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + file: { + title: "阿里云上传", + type: "file-uploader", + form: { + component: { + uploader: { + type: "alioss" + } + } + } + }, + pictureCard: { + title: "照片墙", + type: "image-uploader", + form: { + component: { + uploader: { + type: "alioss" + } + } + } + }, + cropper: { + title: "裁剪", + type: "cropper-uploader", + form: { + component: { + uploader: { + type: "alioss" + } + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/component/uploader/alioss/index.vue b/packages/ui/certd-client/src/views/crud/component/uploader/alioss/index.vue new file mode 100644 index 00000000..0a305710 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/uploader/alioss/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/component/uploader/alioss/mock.js b/packages/ui/certd-client/src/views/crud/component/uploader/alioss/mock.js new file mode 100644 index 00000000..c3de4857 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/uploader/alioss/mock.js @@ -0,0 +1,24 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "AliossUploader", + idGenerator: 0 +}; +const list = [ + { + avatar_error1: "http://greper.handsfree.work/extends/avatar1.jpg", + avatar_error2: "http://greper.handsfree.work/extends/avatar1.jpg", + avatar: "http://greper.handsfree.work/extends/avatar.jpg", + file: ["http://greper.handsfree.work/extends/avatar.jpg", "https://www.baidu.com/img/bd_logo1.png"], + image: ["http://greper.handsfree.work/extends/avatar.jpg", "https://www.baidu.com/img/bd_logo1.png"], + image2: ["http://greper.handsfree.work/extends/avatar.jpg", "https://www.baidu.com/img/bd_logo1.png"] + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/component/uploader/cos/api.js b/packages/ui/certd-client/src/views/crud/component/uploader/cos/api.js new file mode 100644 index 00000000..536456ea --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/uploader/cos/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/CosUploader"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/component/uploader/cos/crud.jsx b/packages/ui/certd-client/src/views/crud/component/uploader/cos/crud.jsx new file mode 100644 index 00000000..05e54e16 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/uploader/cos/crud.jsx @@ -0,0 +1,75 @@ +import * as api from "./api"; +import { requestForMock } from "/src/api/service"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + file: { + title: "腾讯云", + type: "file-uploader", + form: { + component: { + uploader: { + type: "cos" + } + } + } + }, + pictureCard: { + title: "照片墙", + type: "image-uploader", + form: { + component: { + uploader: { + type: "cos" + } + } + } + }, + cropper: { + title: "裁剪", + type: "cropper-uploader", + form: { + component: { + uploader: { + type: "cos" + } + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/component/uploader/cos/index.vue b/packages/ui/certd-client/src/views/crud/component/uploader/cos/index.vue new file mode 100644 index 00000000..8b4bc1ef --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/uploader/cos/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/component/uploader/cos/mock.js b/packages/ui/certd-client/src/views/crud/component/uploader/cos/mock.js new file mode 100644 index 00000000..5c608212 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/uploader/cos/mock.js @@ -0,0 +1,22 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "CosUploader", + idGenerator: 0 +}; +const list = [ + { + avatar: "http://greper.handsfree.work/extends/avatar.jpg", + file: ["http://greper.handsfree.work/extends/avatar.jpg", "https://www.baidu.com/img/bd_logo1.png"], + image: ["http://greper.handsfree.work/extends/avatar.jpg", "https://www.baidu.com/img/bd_logo1.png"], + image2: ["http://greper.handsfree.work/extends/avatar.jpg", "https://www.baidu.com/img/bd_logo1.png"] + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/component/uploader/cropper/api.js b/packages/ui/certd-client/src/views/crud/component/uploader/cropper/api.js new file mode 100644 index 00000000..5113d49c --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/uploader/cropper/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/CropperUploader"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/component/uploader/cropper/crud.jsx b/packages/ui/certd-client/src/views/crud/component/uploader/cropper/crud.jsx new file mode 100644 index 00000000..4d8e168c --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/uploader/cropper/crud.jsx @@ -0,0 +1,110 @@ +import * as api from "./api"; +import { requestForMock } from "/src/api/service"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + cropper: { + title: "头像裁剪上传", + type: "cropper-uploader" + }, + avatar: { + title: "数量限制", + type: "cropper-uploader", + form: { + component: { + limit: 5 //默认限制1个,即头像上传,0为不限制 + } + } + }, + aspect: { + title: "按比例裁剪", + type: "cropper-uploader", + form: { + component: { + cropper: { + aspectRatio: 2 + } + } + } + }, + alioss: { + title: "alioss", + type: "cropper-uploader", + form: { + component: { + uploader: { + type: "alioss" + } + } + } + }, + qiniu: { + title: "七牛", + type: "cropper-uploader", + form: { + component: { + uploader: { + type: "qiniu" + } + } + } + }, + cos: { + title: "腾讯cos", + type: "cropper-uploader", + form: { + component: { + uploader: { + type: "cos" + } + } + } + }, + form: { + title: "表单", + type: "cropper-uploader", + form: { + component: { + uploader: { + type: "form" + } + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/component/uploader/cropper/index.vue b/packages/ui/certd-client/src/views/crud/component/uploader/cropper/index.vue new file mode 100644 index 00000000..3e6a98bf --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/uploader/cropper/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/component/uploader/cropper/mock.js b/packages/ui/certd-client/src/views/crud/component/uploader/cropper/mock.js new file mode 100644 index 00000000..83108782 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/uploader/cropper/mock.js @@ -0,0 +1,24 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "CropperUploader", + idGenerator: 0 +}; +const list = [ + { + avatar_error1: "http://greper.handsfree.work/extends/avatar1.jpg", + avatar_error2: "http://greper.handsfree.work/extends/avatar1.jpg", + avatar: "http://greper.handsfree.work/extends/avatar.jpg", + file: ["http://greper.handsfree.work/extends/avatar.jpg", "https://www.baidu.com/img/bd_logo1.png"], + image: ["http://greper.handsfree.work/extends/avatar.jpg", "https://www.baidu.com/img/bd_logo1.png"], + image2: ["http://greper.handsfree.work/extends/avatar.jpg", "https://www.baidu.com/img/bd_logo1.png"] + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/component/uploader/form/api.js b/packages/ui/certd-client/src/views/crud/component/uploader/form/api.js new file mode 100644 index 00000000..af8d42b4 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/uploader/form/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/ComponentUploader"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/component/uploader/form/crud.jsx b/packages/ui/certd-client/src/views/crud/component/uploader/form/crud.jsx new file mode 100644 index 00000000..7a9cb064 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/uploader/form/crud.jsx @@ -0,0 +1,223 @@ +import * as api from "./api"; +import { AllUploadSuccessValidator } from "@fast-crud/fast-extends"; +import { dict } from "@fast-crud/fast-crud"; +import { nextTick } from "vue"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + form: { + wrapper: { + async onOpened() { + // 异步组件实例的获取 + const componentRef = await expose.getFormComponentRef("file", true); + console.log("componentRef", componentRef); + } + } + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + file: { + title: "表单上传", + type: "file-uploader", + form: { + component: { + multiple: true, //可选择多个 + uploader: { + type: "form" + } + } + }, + column: { + component: { + // 如果你后台返回的值不是一个完整的url,那么展示时就无法显示和点击 + // 需要你本地根据value构建文件的url。 + // 支持异步 + async buildUrl(value) { + return value; + } + } + } + }, + pictureCard: { + title: "照片墙", + type: "image-uploader", + form: { + component: { + limit: 1, + uploader: { + type: "form" + } + }, + helper: "最大可上传1个文件" + }, + column: { + component: { + buildPreviewUrl({ url, index }) { + if (index === 0) { + return "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png"; + } else { + return url + "?preview=600x600"; + } + } + } + } + }, + pictureCard2: { + title: "通过urls显示", + type: "image-uploader", + column: { + component: { + urls: [ + { + url: "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png?1", + previewUrl: "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png?preview1" + }, + { + url: "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png?2", + previewUrl: "https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png?preview2" + } + ] + } + } + }, + avatar: { + title: "头像上传", + type: "avatar-uploader", + form: { + component: { + uploader: { + type: "form" + } + }, + helper: "就是照片墙limit=1的效果" + } + }, + cropper: { + title: "裁剪", + type: "cropper-uploader", + form: { + component: { + uploader: { + type: "form" + } + } + } + }, + keyValueType: { + title: "valueType为key", + type: "file-uploader", + form: { + component: { + uploader: { + type: "form" + }, + valueType: "key", + async buildUrl(value) { + return new Promise((resolve) => { + const url = "http://www.docmirror.cn:7070/api/upload/form/download?key=" + value; + resolve(url); + }); + } + } + }, + column: { + component: { + async buildUrl(value) { + return new Promise((resolve) => { + const url = "http://www.docmirror.cn:7070/api/upload/form/download?key=" + value; + resolve(url); + }); + } + } + } + }, + limit: { + title: "限制数量", + type: "file-uploader", + form: { + component: { + limit: 2, + uploader: { + type: "form" + } + }, + helper: "最大可上传2个文件" + } + }, + sizeLimit: { + title: "限制大小", + type: "file-uploader", + form: { + component: { + sizeLimit: 1024, + uploader: { + type: "form" + } + }, + helper: "大小不能超过1k" + } + }, + accept: { + title: "限制类型", + type: "file-uploader", + form: { + component: { + accept: "*.jpg,*.png" + }, + helper: "只能上传jpg或者png" + } + }, + validation: { + title: "校验", + type: "file-uploader", + form: { + rules: [ + { required: true, message: "此项必传" }, + { + validator: AllUploadSuccessValidator(), //如果要自定义校验规则则需要手动配置这个 + message: "还有文件正在上传,请稍候" + } + ], + helper: "大小不能超过50M,文件未上传完成之前,阻止提交", + component: { + uploader: { + type: "form", + sizeLimit: 1024 * 1024 * 50 + } + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/component/uploader/form/index.vue b/packages/ui/certd-client/src/views/crud/component/uploader/form/index.vue new file mode 100644 index 00000000..eaae1cac --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/uploader/form/index.vue @@ -0,0 +1,43 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/component/uploader/form/mock.js b/packages/ui/certd-client/src/views/crud/component/uploader/form/mock.js new file mode 100644 index 00000000..e4fda8db --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/uploader/form/mock.js @@ -0,0 +1,24 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "ComponentUploader", + idGenerator: 0 +}; +const list = [ + { + avatar: "http://greper.handsfree.work/extends/avatar.jpg", + file: ["http://greper.handsfree.work/extends/avatar.jpg", "https://www.baidu.com/img/bd_logo1.png"], + pictureCard: ["http://greper.handsfree.work/extends/avatar.jpg", "https://www.baidu.com/img/bd_logo1.png"], + limit: ["http://greper.handsfree.work/extends/avatar.jpg", "https://www.baidu.com/img/bd_logo1.png"], + statusRemote: "0", + keyValueType: "/2022-12-20/qygzqdjd1g.yaml" + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/component/uploader/qiniu/api.js b/packages/ui/certd-client/src/views/crud/component/uploader/qiniu/api.js new file mode 100644 index 00000000..2d79f7b5 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/uploader/qiniu/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/QiniuUploader"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/component/uploader/qiniu/crud.jsx b/packages/ui/certd-client/src/views/crud/component/uploader/qiniu/crud.jsx new file mode 100644 index 00000000..89c787c3 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/uploader/qiniu/crud.jsx @@ -0,0 +1,73 @@ +import * as api from "./api"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + file: { + title: "七牛云上传", + type: "file-uploader", + form: { + component: { + uploader: { + type: "qiniu" + } + } + } + }, + pictureCard: { + title: "照片墙", + type: "image-uploader", + form: { + component: { + uploader: { + type: "qiniu" + } + } + } + }, + cropper: { + title: "裁剪", + type: "cropper-uploader", + form: { + component: { + uploader: { + type: "qiniu" + } + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/component/uploader/qiniu/index.vue b/packages/ui/certd-client/src/views/crud/component/uploader/qiniu/index.vue new file mode 100644 index 00000000..0a305710 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/uploader/qiniu/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/component/uploader/qiniu/mock.js b/packages/ui/certd-client/src/views/crud/component/uploader/qiniu/mock.js new file mode 100644 index 00000000..45c79685 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/component/uploader/qiniu/mock.js @@ -0,0 +1,22 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "QiniuUploader", + idGenerator: 0 +}; +const list = [ + { + avatar: "http://greper.handsfree.work/extends/avatar.jpg", + file: ["http://greper.handsfree.work/extends/avatar.jpg", "https://www.baidu.com/img/bd_logo1.png"], + image: ["http://greper.handsfree.work/extends/avatar.jpg", "https://www.baidu.com/img/bd_logo1.png"], + image2: ["http://greper.handsfree.work/extends/avatar.jpg", "https://www.baidu.com/img/bd_logo1.png"] + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/debug/select/api.js b/packages/ui/certd-client/src/views/crud/debug/select/api.js new file mode 100644 index 00000000..06a6bd3e --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/debug/select/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/DebugSelect"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/debug/select/crud.jsx b/packages/ui/certd-client/src/views/crud/debug/select/crud.jsx new file mode 100644 index 00000000..d3bee612 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/debug/select/crud.jsx @@ -0,0 +1,106 @@ +import * as api from "./api"; +import { requestForMock } from "/src/api/service"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + form: { + // 单列布局 + col: { span: 24 }, + labelCol: { span: 4 }, + wrapperCol: { span: 18 } + }, + rowHandle: { + fixed: "right" + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + + statusRemote: { + title: "单选远程", + search: { + show: true, + value: [] + }, + type: "dict-select", + dict: dict({ + url: "/mock/dicts/_OpenStatusEnum2?simple", + value: "id", + label: "text" + }), + form: { + component: { mode: "multiple" }, + rules: [{ required: true, message: "请选择一个选项" }] + }, + column: { + width: 200 + } + }, + id2: { + title: "ID", + key: "id", + type: "number", + column: { + width: 300 + }, + form: { + show: false + } + }, + id3: { + title: "ID", + key: "id", + type: "number", + column: { + width: 300 + }, + form: { + show: false + } + }, + id4: { + title: "ID", + key: "id", + type: "number", + column: { + width: 300 + }, + form: { + show: false + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/debug/select/index.vue b/packages/ui/certd-client/src/views/crud/debug/select/index.vue new file mode 100644 index 00000000..e7105c52 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/debug/select/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/debug/select/mock.js b/packages/ui/certd-client/src/views/crud/debug/select/mock.js new file mode 100644 index 00000000..2cb1e175 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/debug/select/mock.js @@ -0,0 +1,9 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "DebugSelect", + idGenerator: 0 +}; +const list = []; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/dict/cloneable/api.js b/packages/ui/certd-client/src/views/crud/dict/cloneable/api.js new file mode 100644 index 00000000..a6c63db5 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/cloneable/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/DictCloneable"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/dict/cloneable/crud.jsx b/packages/ui/certd-client/src/views/crud/dict/cloneable/crud.jsx new file mode 100644 index 00000000..4ad17c78 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/cloneable/crud.jsx @@ -0,0 +1,88 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + const remoteDict = dict({ + cloneable: true, + url: "/mock/dicts/OpenStatusEnum" + }); + + return { + crudOptions: { + remoteDict, + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + remote: { + title: "远程字典", + search: { show: true }, + dict: remoteDict, + type: "dict-select", + form: { + component: { dict: { cache: false } } + } + }, + modifyDict: { + title: "动态修改字典", + search: { show: false }, + type: "text", + column: { + component: { + name: "a-switch", + vModel: "checked" + }, + valueChange({ row, getComponentRef }) { + // 这里不能使用remoteDict,因为在分发时已经clone到form配置中了 + // 这里dict修改不会影响列里面的数据 + const targetDict = getComponentRef("remote").dict; + targetDict.url = row.modifyDict ? "/mock/dicts/moreOpenStatusEnum?remote" : "/mock/dicts/OpenStatusEnum?remote"; + targetDict.reloadDict(); + } + }, + form: { + component: { + name: "a-switch", + vModel: "checked" + }, + valueChange({ form, getComponentRef }) { + // 这里不能使用remoteDict,因为在分发时已经clone到form配置中了 + // 这里dict修改不会影响列里面的数据 + const targetDict = getComponentRef("remote").dict; + targetDict.url = form.modifyDict ? "/mock/dicts/moreOpenStatusEnum?remote" : "/mock/dicts/OpenStatusEnum?remote"; + targetDict.reloadDict(); + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/dict/cloneable/index.vue b/packages/ui/certd-client/src/views/crud/dict/cloneable/index.vue new file mode 100644 index 00000000..4850b620 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/cloneable/index.vue @@ -0,0 +1,48 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/dict/cloneable/mock.js b/packages/ui/certd-client/src/views/crud/dict/cloneable/mock.js new file mode 100644 index 00000000..acb0f31b --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/cloneable/mock.js @@ -0,0 +1,21 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "DictCloneable", + idGenerator: 0 +}; +const list = [ + { + status: "1", + remote: "2" + }, + { + status: "2", + remote: "0" + }, + { + status: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/dict/prototype/api.js b/packages/ui/certd-client/src/views/crud/dict/prototype/api.js new file mode 100644 index 00000000..08ab8195 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/prototype/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/DictPrototype"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/dict/prototype/crud.jsx b/packages/ui/certd-client/src/views/crud/dict/prototype/crud.jsx new file mode 100644 index 00000000..c40a2b07 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/prototype/crud.jsx @@ -0,0 +1,128 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +import { requestForMock } from "../../../../api/service"; + +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + const remoteDict = dict({ + prototype: true, //这个dict只是一个原型,引用它的dict组件初始化时都会把此dict对象clone一份 + url: "/mock/dicts/OpenStatusEnum" + }); + + const dynamicUrlDict = dict({ + cache: true, + prototype: true, //这个dict只是一个原型,引用它的dict组件初始化时都会把此dict对象clone一份 + url({ row }) { + return row.switch ? "/mock/dicts/moreOpenStatusEnum" : "/mock/dicts/OpenStatusEnum"; + } + }); + const dynamicDict = dict({ + cache: true, + prototype: true, //这个dict只是一个原型,引用它的dict组件初始化时都会把此dict对象clone一份 + url({ row }) { + return row.switch ? "/mock/dicts/moreOpenStatusEnum" : "/mock/dicts/OpenStatusEnum"; + }, + async getData({ url }) { + return await requestForMock({ url }); + } + }); + + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + remote: { + title: "远程字典", + search: { show: true }, + dict: remoteDict, + type: "dict-select" + }, + modifyDict: { + title: "动态修改字典", + search: { show: true }, + type: "text", + form: { + helper: "此处可以动态切换左边select的options", + component: { + name: "a-switch", + vModel: "checked" + }, + valueChange({ form, value, getComponentRef }) { + console.log("form", value); + const targetDict = getComponentRef("remote").getDict(); + targetDict.url = form.modifyDict + ? "/mock/dicts/moreOpenStatusEnum?remote" + : "/mock/dicts/OpenStatusEnum?remote"; + targetDict.reloadDict(); + } + }, + column: { + component: { + name: "a-switch", + vModel: "checked" + }, + valueChange({ value, getComponentRef }) { + console.log("value", value); + const targetDict = getComponentRef("remote").getDict(); + targetDict.url = value ? "/mock/dicts/moreOpenStatusEnum?remote" : "/mock/dicts/OpenStatusEnum?remote"; + targetDict.reloadDict(); + } + } + }, + switch: { + title: "switch", + type: "dict-switch", + dict: dict({ + data: [ + { value: true, label: "开启" }, + { value: false, label: "关闭" } + ] + }), + form: { + helper: "动态getData和动态Url根据此字段的值获取不同的dictData,此处无法动态切换,仅在打开对话框时生效" + } + }, + dynamicGetData: { + title: "动态getData", + dict: dynamicDict, + type: "dict-select" + }, + dynamicUrl: { + title: "动态Url", + dict: dynamicUrlDict, + type: "dict-select" + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/dict/prototype/index.vue b/packages/ui/certd-client/src/views/crud/dict/prototype/index.vue new file mode 100644 index 00000000..1adcdfaa --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/prototype/index.vue @@ -0,0 +1,48 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/dict/prototype/mock.js b/packages/ui/certd-client/src/views/crud/dict/prototype/mock.js new file mode 100644 index 00000000..adc12b8a --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/prototype/mock.js @@ -0,0 +1,31 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "DictPrototype", + idGenerator: 0 +}; +const list = [ + { + status: "1", + remote: "2", + modifyDict: false, + switch: true, + dynamicGetData: "1", + dynamicUrl: "2" + }, + { + status: "2", + remote: "0", + modifyDict: false, + dynamicGetData: "1", + dynamicUrl: "2" + }, + { + status: "0", + modifyDict: false, + dynamicGetData: "1", + dynamicUrl: "2" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/dict/shared/manager/api.js b/packages/ui/certd-client/src/views/crud/dict/shared/manager/api.js new file mode 100644 index 00000000..0d2a093f --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/shared/manager/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/DictSharedManager"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/dict/shared/manager/crud.tsx b/packages/ui/certd-client/src/views/crud/dict/shared/manager/crud.tsx new file mode 100644 index 00000000..5293f502 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/shared/manager/crud.tsx @@ -0,0 +1,58 @@ +import * as api from "./api"; +import { statusDict } from "../shared-dict"; +export default function ({ crudExpose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + pagination: { + pageSize: 9999 + }, + table: { + onRefreshed({ data }) { + statusDict.setData(data); + } + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + name: { + title: "name", + type: "text" + }, + label: { + title: "标签", + type: "text" + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/dict/shared/manager/index.vue b/packages/ui/certd-client/src/views/crud/dict/shared/manager/index.vue new file mode 100644 index 00000000..da55bca0 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/shared/manager/index.vue @@ -0,0 +1,33 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/dict/shared/manager/mock.js b/packages/ui/certd-client/src/views/crud/dict/shared/manager/mock.js new file mode 100644 index 00000000..d99468cb --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/shared/manager/mock.js @@ -0,0 +1,23 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "DictSharedManager", + idGenerator: 0, + copyTimes: 1 +}; +const list = [ + { + name: "close", + label: "关闭" + }, + { + name: "open", + label: "打开" + }, + { + name: "stop", + label: "停止" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/dict/shared/shared-dict.ts b/packages/ui/certd-client/src/views/crud/dict/shared/shared-dict.ts new file mode 100644 index 00000000..606f93ae --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/shared/shared-dict.ts @@ -0,0 +1,10 @@ +import { dict, utils } from "@fast-crud/fast-crud"; +import * as api from "./manager/api"; +export const statusDict = dict({ + value: "name", + async getData() { + const res = await api.GetList({ query: {}, sort: {}, page: { limit: 9999 } }); + utils.logger.debug("status dict first loaded", res.records); + return res.records; + } +}); diff --git a/packages/ui/certd-client/src/views/crud/dict/shared/use/api.js b/packages/ui/certd-client/src/views/crud/dict/shared/use/api.js new file mode 100644 index 00000000..c2bdbc91 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/shared/use/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/DictSharedUse"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/dict/shared/use/crud.jsx b/packages/ui/certd-client/src/views/crud/dict/shared/use/crud.jsx new file mode 100644 index 00000000..f2f566d5 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/shared/use/crud.jsx @@ -0,0 +1,47 @@ +import * as api from "./api"; +import { statusDict } from "../shared-dict"; +export default function ({ crudExpose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + status: { + title: "状态", + type: "dict-select", + dict: statusDict + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/dict/shared/use/index.vue b/packages/ui/certd-client/src/views/crud/dict/shared/use/index.vue new file mode 100644 index 00000000..547dc92d --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/shared/use/index.vue @@ -0,0 +1,33 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/dict/shared/use/mock.js b/packages/ui/certd-client/src/views/crud/dict/shared/use/mock.js new file mode 100644 index 00000000..b7c65bf3 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/shared/use/mock.js @@ -0,0 +1,19 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "DictSharedUse", + idGenerator: 0 +}; +const list = [ + { + status: "close" + }, + { + status: "stop" + }, + { + status: "open" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/dict/single/api.js b/packages/ui/certd-client/src/views/crud/dict/single/api.js new file mode 100644 index 00000000..97193654 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/single/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/DictSingle"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/dict/single/crud.jsx b/packages/ui/certd-client/src/views/crud/dict/single/crud.jsx new file mode 100644 index 00000000..aa161d64 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/single/crud.jsx @@ -0,0 +1,111 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + const statusDict = dict({ + cloneable: false, // 关闭cloneable,任何情况下,都使用同一个dict + data: [ + { value: "1", label: "开启", color: "success" }, + { value: "2", label: "停止", color: "blue" }, + { value: "0", label: "关闭", color: "blue" } + ] + }); + + const remoteDict = dict({ + cloneable: false, // 关闭cloneable,任何情况下,都使用同一个dict + url: "/mock/dicts/OpenStatusEnum", + immediate: false + }); + // remoteDict.loadDict(); + + return { + remoteDict, + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + status: { + title: "本地字典", + search: { show: false }, + dict: statusDict, + type: "dict-select" + }, + remote: { + title: "远程字典", + search: { show: true }, + dict: remoteDict, + type: "dict-select", + column: { + component: { + onDictChange(opts) { + console.log("字典变化:", opts); + } + } + } + }, + modifyDict: { + title: "动态修改字典", + search: { show: false }, + type: "text", + form: { + component: { + name: "a-switch", + vModel: "checked" + }, + valueChange({ form }) { + console.log("changed", form.modifyDict); + remoteDict.url = form.modifyDict + ? "/mock/dicts/moreOpenStatusEnum?remote" + : "/mock/dicts/OpenStatusEnum?remote"; + // 由于remoteDict.cloneable =false,所以全局公用一个实例,修改会影响全部地方 + remoteDict.reloadDict(); + } + }, + column: { + component: { + name: "a-switch", + vModel: "checked", + on: { + // 注意:必须要on前缀 + onChange({ $event }) { + remoteDict.url = $event + ? "/mock/dicts/moreOpenStatusEnum?remote" + : "/mock/dicts/OpenStatusEnum?remote"; + remoteDict.reloadDict(); + } + } + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/dict/single/index.vue b/packages/ui/certd-client/src/views/crud/dict/single/index.vue new file mode 100644 index 00000000..a0f6a2d0 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/single/index.vue @@ -0,0 +1,49 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/dict/single/mock.js b/packages/ui/certd-client/src/views/crud/dict/single/mock.js new file mode 100644 index 00000000..cad375c9 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/dict/single/mock.js @@ -0,0 +1,21 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "DictSingle", + idGenerator: 0 +}; +const list = [ + { + status: "1", + remote: "2" + }, + { + status: "2", + remote: "0" + }, + { + status: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/column-resize/api.js b/packages/ui/certd-client/src/views/crud/feature/column-resize/api.js new file mode 100644 index 00000000..279509cc --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/column-resize/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FeatureSearch"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/feature/column-resize/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/column-resize/crud.jsx new file mode 100644 index 00000000..913909db --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/column-resize/crud.jsx @@ -0,0 +1,70 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +import { ref } from "vue"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + const crudBinding = expose.crudBinding; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + table: { + onResizeColumn: (w, col) => { + //触发resize事件后,修改column宽度,width只能配置为number类型 + //可以将此方法写在app.use()中的commonOptions里面 + crudBinding.value.table.columnsMap[col.key].width = w; + } + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50, //宽度必须number类型 + resizable: true //配置true,表示可以调整宽度 + }, + form: { + show: false + } + }, + text: { + title: "说明", + type: "text", + column: { + ellipsis: true, + showTitle: true, + resizable: true, //配置true,表示可以调整宽度 + width: 400 //宽度必须number类型 + } + }, + //必须留一个自动宽度 + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/column-resize/index.vue b/packages/ui/certd-client/src/views/crud/feature/column-resize/index.vue new file mode 100644 index 00000000..8565e9e6 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/column-resize/index.vue @@ -0,0 +1,43 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/column-resize/mock.js b/packages/ui/certd-client/src/views/crud/feature/column-resize/mock.js new file mode 100644 index 00000000..68cfb67a --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/column-resize/mock.js @@ -0,0 +1,20 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FeatureSearch", + idGenerator: 0 +}; +const list = [ + { + text: "这一列可以调整宽度,另外必须留一列自动宽度", + radio: "1" + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/column-sort/api.js b/packages/ui/certd-client/src/views/crud/feature/column-sort/api.js new file mode 100644 index 00000000..37c27d57 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/column-sort/api.js @@ -0,0 +1,50 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FeatureColumnSort"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} + +export function BatchDelete(ids) { + return request({ + url: apiPrefix + "/batchDelete", + method: "post", + data: { ids } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/feature/column-sort/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/column-sort/crud.jsx new file mode 100644 index 00000000..fbadd388 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/column-sort/crud.jsx @@ -0,0 +1,94 @@ +import * as api from "./api"; +export default function ({ expose }) { + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + return { + crudOptions: { + request: { + pageRequest: api.GetList, + addRequest, + editRequest, + delRequest + }, + toolbar: { + //工具按钮排序 + buttons: { + search: { order: 1 } // 查询按钮排到前面 + } + }, + form: { + //表单跨列 + col: { span: 24 }, + labelCol: { span: 6 } + }, + columns: { + col1: { + title: "col.1", + search: { show: true }, + type: "text" + }, + col2: { + title: "col.2,我排最后一个", + search: { + //控制查询字段顺序 + show: true, + //字段默认order为100,比100大的放最后面 + order: 101 + }, + type: "text", + column: { + //控制列字段顺序 + //字段默认order为100,比100大的放最后面 + order: 101 + }, + form: { + //控制表单字段顺序 + //字段默认order为100,比100大的放最后面 + order: 101 + } + }, + col3: { + title: "col.3,我排第一个", + search: { + show: true, + order: 0 + }, + type: "text", + column: { + order: 0 + }, + form: { + order: 0 + } + }, + col4: { + title: "col.4,我在col3后面", + type: "text", + search: { + show: true, + order: 0 + }, + column: { + order: 0 + }, + form: { + order: 0 + } + }, + col5: { + title: "col.5", + type: "text" + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/column-sort/index.vue b/packages/ui/certd-client/src/views/crud/feature/column-sort/index.vue new file mode 100644 index 00000000..4f86ebea --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/column-sort/index.vue @@ -0,0 +1,47 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/column-sort/mock.js b/packages/ui/certd-client/src/views/crud/feature/column-sort/mock.js new file mode 100644 index 00000000..66315f55 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/column-sort/mock.js @@ -0,0 +1,31 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FeatureColumnSort", + idGenerator: 0 +}; +const list = [ + { + col1: "1", + col2: "2", + col3: "3", + col4: "4", + col5: "5" + }, + { + col1: "1", + col2: "2", + col3: "3", + col4: "4", + col5: "5" + }, + { + col1: "1", + col2: "2", + col3: "3", + col4: "4", + col5: "5" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/columns-set/api.js b/packages/ui/certd-client/src/views/crud/feature/columns-set/api.js new file mode 100644 index 00000000..b3a57257 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/columns-set/api.js @@ -0,0 +1,50 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FeatureColumnsSet"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} + +export function BatchDelete(ids) { + return request({ + url: apiPrefix + "/batchDelete", + method: "post", + data: { ids } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/feature/columns-set/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/columns-set/crud.jsx new file mode 100644 index 00000000..3099f8b9 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/columns-set/crud.jsx @@ -0,0 +1,55 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +import { ref } from "vue"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + toolbar: { + columnsFilter: { + mode: "simple" + } + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/columns-set/index.vue b/packages/ui/certd-client/src/views/crud/feature/columns-set/index.vue new file mode 100644 index 00000000..5c898b19 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/columns-set/index.vue @@ -0,0 +1,49 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/columns-set/mock.js b/packages/ui/certd-client/src/views/crud/feature/columns-set/mock.js new file mode 100644 index 00000000..79043c91 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/columns-set/mock.js @@ -0,0 +1,19 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FeatureColumnsSet", + idGenerator: 0 +}; +const list = [ + { + radio: "1" + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/editable-row/api.js b/packages/ui/certd-client/src/views/crud/feature/editable-row/api.js new file mode 100644 index 00000000..acb0aab5 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/editable-row/api.js @@ -0,0 +1,50 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FeatureEditableRow"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} + +export function BatchDelete(ids) { + return request({ + url: apiPrefix + "/batchDelete", + method: "post", + data: { ids } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/feature/editable-row/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/editable-row/crud.jsx new file mode 100644 index 00000000..4b4c8784 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/editable-row/crud.jsx @@ -0,0 +1,88 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + const id = await api.AddObj(form); + return { id }; + }; + + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + actionbar: { buttons: { add: { show: false }, addRow: { show: true } } }, + table: { + editable: { + enabled: true, + mode: "row", + activeTrigger: false + } + }, + columns: { + id: { + title: "ID", + type: "number", + form: { + show: false + }, + column: { width: 80, align: "center" } + }, + disable: { + title: "禁止编辑", + type: "text", + column: { + editable: { + disabled: true //也可以配置为方法,根据条件禁用或启用编辑 + // disabled: ({ column, index, row }) => { + // return index % 2 === 0; + // } + } + } + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + }, + name: { + title: "姓名", + type: "text" + }, + province: { + title: "省份", + search: { show: true }, + type: "dict-select", + dict: dict({ + value: "id", + label: "text", + data: [ + { id: "sz", text: "深圳", color: "success" }, + { id: "gz", text: "广州", color: "primary" }, + { id: "bj", text: "北京" }, + { id: "wh", text: "武汉" }, + { id: "sh", text: "上海" } + ] + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/editable-row/index.vue b/packages/ui/certd-client/src/views/crud/feature/editable-row/index.vue new file mode 100644 index 00000000..54f2c697 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/editable-row/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/editable-row/mock.js b/packages/ui/certd-client/src/views/crud/feature/editable-row/mock.js new file mode 100644 index 00000000..9a11dbb2 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/editable-row/mock.js @@ -0,0 +1,19 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FeatureEditableRow", + idGenerator: 0 +}; +const list = [ + { + radio: "1" + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/editable/api.js b/packages/ui/certd-client/src/views/crud/feature/editable/api.js new file mode 100644 index 00000000..e3cf94ec --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/editable/api.js @@ -0,0 +1,50 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FeatureEditable"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} + +export function BatchDelete(ids) { + return request({ + url: apiPrefix + "/batchDelete", + method: "post", + data: { ids } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/feature/editable/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/editable/crud.jsx new file mode 100644 index 00000000..72d8d608 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/editable/crud.jsx @@ -0,0 +1,105 @@ +import * as api from "./api"; +import { dict, compute } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const { crudBinding } = expose; + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + actionbar: { + buttons: { + add: { + show: compute(() => { + if (crudBinding.value) { + return !crudBinding.value?.table.editable.enabled; + } + return false; + }) + }, + addRow: { + show: compute(() => { + if (crudBinding.value) { + return crudBinding.value?.table.editable.enabled; + } + return false; + }) + } + } + }, + table: { + editable: { + mode: "free" + } + }, + columns: { + id: { + title: "ID", + type: "number", + form: { + show: false + }, + column: { width: 80, align: "center" } + }, + disable: { + title: "禁止编辑", + type: "text", + column: { + editable: { + disabled: true //也可以配置为方法,根据条件禁用或启用编辑 + // disabled: ({ column, index, row }) => { + // return index % 2 === 0; + // } + } + } + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + }, + name: { + title: "姓名", + type: "text" + }, + province: { + title: "省份", + search: { show: true }, + type: "dict-select", + dict: dict({ + value: "id", + label: "text", + data: [ + { id: "sz", text: "深圳", color: "success" }, + { id: "gz", text: "广州", color: "primary" }, + { id: "bj", text: "北京" }, + { id: "wh", text: "武汉" }, + { id: "sh", text: "上海" } + ] + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/editable/index.vue b/packages/ui/certd-client/src/views/crud/feature/editable/index.vue new file mode 100644 index 00000000..e7280e8a --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/editable/index.vue @@ -0,0 +1,100 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/editable/mock.js b/packages/ui/certd-client/src/views/crud/feature/editable/mock.js new file mode 100644 index 00000000..b1d6b08d --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/editable/mock.js @@ -0,0 +1,19 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FeatureEditable", + idGenerator: 0 +}; +const list = [ + { + radio: "1" + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/expand/api.js b/packages/ui/certd-client/src/views/crud/feature/expand/api.js new file mode 100644 index 00000000..c9ad003b --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/expand/api.js @@ -0,0 +1,50 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FeatureExpand"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} + +export function BatchDelete(ids) { + return request({ + url: apiPrefix + "/batchDelete", + method: "post", + data: { ids } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/feature/expand/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/expand/crud.jsx new file mode 100644 index 00000000..5a3dee3f --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/expand/crud.jsx @@ -0,0 +1,63 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +import { ref } from "vue"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + table: { + //默认展开第一行 + defaultExpandedRowKeys:[1], + slots: { + expandedRowRender: (scope) => { + return ( +
+ index: {scope.index} ; row: {JSON.stringify(scope.record)} +
+ ); + } + } + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/expand/index.vue b/packages/ui/certd-client/src/views/crud/feature/expand/index.vue new file mode 100644 index 00000000..fe8b3d2c --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/expand/index.vue @@ -0,0 +1,65 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/expand/mock.js b/packages/ui/certd-client/src/views/crud/feature/expand/mock.js new file mode 100644 index 00000000..3b6d6944 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/expand/mock.js @@ -0,0 +1,19 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FeatureExpand", + idGenerator: 0 +}; +const list = [ + { + radio: "1" + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/filter/api.js b/packages/ui/certd-client/src/views/crud/feature/filter/api.js new file mode 100644 index 00000000..6970dae3 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/filter/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FeatureFilter"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/feature/filter/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/filter/crud.jsx new file mode 100644 index 00000000..672d8911 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/filter/crud.jsx @@ -0,0 +1,70 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +import { ref } from "vue"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + table: { + // 表头过滤改变事件 + onFilterChange(e) { + console.log("onFilterChange", e); + } + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }), + column: { + filters: [ + { text: "开", value: "1" }, + { text: "关", value: "0" }, + { text: "停", value: "2" } + ], + // specify the condition of filtering result + // here is that finding the name started with `value` + onFilter: (value, record) => { + return record.radio === value; + }, + sorter: (a, b) => a.radio - b.radio, + sortDirections: ["descend"] + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/filter/index.vue b/packages/ui/certd-client/src/views/crud/feature/filter/index.vue new file mode 100644 index 00000000..7205a947 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/filter/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/filter/mock.js b/packages/ui/certd-client/src/views/crud/feature/filter/mock.js new file mode 100644 index 00000000..fd405168 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/filter/mock.js @@ -0,0 +1,19 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FeatureFilter", + idGenerator: 0 +}; +const list = [ + { + radio: "1" + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/fixed/api.js b/packages/ui/certd-client/src/views/crud/feature/fixed/api.js new file mode 100644 index 00000000..ac40ccaf --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/fixed/api.js @@ -0,0 +1,50 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FeatureFixed"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} + +export function BatchDelete(ids) { + return request({ + url: apiPrefix + "/batchDelete", + method: "post", + data: { ids } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/feature/fixed/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/fixed/crud.jsx new file mode 100644 index 00000000..9b15c1ec --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/fixed/crud.jsx @@ -0,0 +1,90 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + return { + crudOptions: { + request: { + pageRequest: api.GetList, + addRequest, + editRequest, + delRequest + }, + rowHandle: { + //固定右侧 + fixed: "right" + }, + table: { + scroll: { + //当你表格宽度大到需要使用固定列时,需要设置此值,并且是大于等于列宽度之和的值 + //否则可能会出现将自动宽度列挤变形,或者拖动滚动条表头不动等问题。 + x: 1400 + } + }, + columns: { + text1: { + title: "text1", + type: "text", + column: { + // 固定左侧 + // 注意被固定在左侧的列要放在最前面,否则会出现某些列错位不显示的问题 + fixed: "left", + width: 260 + } + }, + id: { + title: "id", + type: "text", + column: { + width: 100 + } + }, + text2: { + title: "text2", + type: "text", + column: { + width: 260 + } + }, + text3: { + title: "text3", + type: "text", + column: { + width: 260 + } + }, + text4: { + title: "text4", + type: "text", + column: { + width: 260 + } + }, + text5: { + title: "text5", + type: "text", + column: { + width: 260 + } + }, + last: { + title: "last", + type: "text", + column: { + width: 260 + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/fixed/index.vue b/packages/ui/certd-client/src/views/crud/feature/fixed/index.vue new file mode 100644 index 00000000..2e1d2ddf --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/fixed/index.vue @@ -0,0 +1,39 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/fixed/mock.js b/packages/ui/certd-client/src/views/crud/feature/fixed/mock.js new file mode 100644 index 00000000..22bd02c4 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/fixed/mock.js @@ -0,0 +1,14 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FeatureFixed", + idGenerator: 0 +}; +const list = [ + { + text1: "我会被固定在左侧", + last: "操作列被固定在右侧" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/header-group/api.js b/packages/ui/certd-client/src/views/crud/feature/header-group/api.js new file mode 100644 index 00000000..4af20b76 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/header-group/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FeatureHeaderGroup"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/feature/header-group/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/header-group/crud.jsx new file mode 100644 index 00000000..09819296 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/header-group/crud.jsx @@ -0,0 +1,109 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + table: { size: "small" }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + user: { + title: "用户信息", + children: { + name: { + title: "姓名", + type: "text" + }, + age: { + title: "年龄", + type: "number" + }, + switch: { + title: "开关", + type: "dict-switch", + dict: dict({ + data: [ + { value: true, label: "开启" }, + { value: false, label: "关闭" } + ] + }), + column: { + component: { + name: "fs-dict-switch", + vModel: "checked" + }, + valueChange(context) { + console.log("column value changed:", context); + } + } + } + } + }, + address: { + title: "地址", + children: { + area: { + title: "地区", + children: { + province: { + title: "省", + search: { show: true }, + type: "dict-select", + dict: dict({ + data: [ + { value: "广东省", label: "广东省" }, + { value: "浙江省", label: "浙江省" } + ] + }) + }, + city: { + title: "市", + search: { show: true }, + type: "text" + }, + county: { + title: "区", + search: { show: true }, + type: "text" + } + } + }, + street: { + title: "街道", + type: "text" + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/header-group/index.vue b/packages/ui/certd-client/src/views/crud/feature/header-group/index.vue new file mode 100644 index 00000000..77c344ff --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/header-group/index.vue @@ -0,0 +1,42 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/header-group/mock.js b/packages/ui/certd-client/src/views/crud/feature/header-group/mock.js new file mode 100644 index 00000000..05760a73 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/header-group/mock.js @@ -0,0 +1,30 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FeatureHeaderGroup", + idGenerator: 0 +}; +const list = [ + { + name: "张三", + age: 18, + province: "广东省", + city: "深圳市", + county: "南山区", + street: "粤海街道" + }, + { + name: "李四", + age: 26, + province: "浙江省", + city: "杭州市", + county: "西湖区", + street: "西湖街道" + }, + { + name: "王五", + age: 24 + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/height/api.js b/packages/ui/certd-client/src/views/crud/feature/height/api.js new file mode 100644 index 00000000..4f5c7d11 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/height/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/ComponentHeight"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/feature/height/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/height/crud.jsx new file mode 100644 index 00000000..ecd5350d --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/height/crud.jsx @@ -0,0 +1,57 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + container: { + fixedHeight: false + }, + table: { + scroll: { + y: null + } + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/height/index.vue b/packages/ui/certd-client/src/views/crud/feature/height/index.vue new file mode 100644 index 00000000..34e52d62 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/height/index.vue @@ -0,0 +1,42 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/height/mock.js b/packages/ui/certd-client/src/views/crud/feature/height/mock.js new file mode 100644 index 00000000..594f6639 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/height/mock.js @@ -0,0 +1,24 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "ComponentHeight", + idGenerator: 0 +}; +const list = [ + { + radio: "1", + button: "1", + bool: true + }, + { + radio: "2", + button: "2", + bool: false + }, + { + radio: "0", + button: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/hide/api.js b/packages/ui/certd-client/src/views/crud/feature/hide/api.js new file mode 100644 index 00000000..dd73bbf3 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/hide/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FeatureHide"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/feature/hide/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/hide/crud.jsx new file mode 100644 index 00000000..27d53eda --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/hide/crud.jsx @@ -0,0 +1,100 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + search: { + show: true + }, + pagination: { + show: true + }, + table: { + show: true + }, + actionbar: { + show: true, + buttons: { + add: { + show: true + }, + test: { + text: "自定义按钮", + show: true, + click() { + console.log("click"); + } + } + } + }, + toolbar: { + show: true, + buttons: { + search: { show: true }, + refresh: { show: true }, + compact: { show: true }, + export: { show: true }, + columns: { show: true } + } + }, + rowHandle: { + show: true, + width: 330, + buttons: { + view: { show: true }, + edit: { show: true }, + remove: { show: true }, + custom: { + text: "自定义", + order: 4, + show: true, + click(context) { + console.log("click", context); + } + } + } + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/hide/index.vue b/packages/ui/certd-client/src/views/crud/feature/hide/index.vue new file mode 100644 index 00000000..454fa5a3 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/hide/index.vue @@ -0,0 +1,184 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/hide/mock.js b/packages/ui/certd-client/src/views/crud/feature/hide/mock.js new file mode 100644 index 00000000..6876a94c --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/hide/mock.js @@ -0,0 +1,19 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FeatureHide", + idGenerator: 0 +}; +const list = [ + { + radio: "1" + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/index/api.js b/packages/ui/certd-client/src/views/crud/feature/index/api.js new file mode 100644 index 00000000..4cf33ea3 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/index/api.js @@ -0,0 +1,50 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FeatureIndex"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} + +export function BatchDelete(ids) { + return request({ + url: apiPrefix + "/batchDelete", + method: "post", + data: { ids } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/feature/index/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/index/crud.jsx new file mode 100644 index 00000000..5c3f3105 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/index/crud.jsx @@ -0,0 +1,56 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + table: {}, + columns: { + _index: { + title: "序号", + form: { show: false }, + column: { + // type: "index", + align: "center", + width: "55px", + columnSetDisabled: true, //禁止在列设置中选择 + formatter: (context) => { + //计算序号,你可以自定义计算规则,此处为翻页累加 + let index = context.index ?? 1; + let pagination = expose.crudBinding.value.pagination; + return ((pagination.currentPage ?? 1) - 1) * pagination.pageSize + index + 1; + } + } + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/index/index.vue b/packages/ui/certd-client/src/views/crud/feature/index/index.vue new file mode 100644 index 00000000..06c33b2b --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/index/index.vue @@ -0,0 +1,39 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/index/mock.js b/packages/ui/certd-client/src/views/crud/feature/index/mock.js new file mode 100644 index 00000000..6e10439f --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/index/mock.js @@ -0,0 +1,19 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FeatureIndex", + idGenerator: 0 +}; +const list = [ + { + radio: "1" + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/local-v-model/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/local-v-model/crud.jsx new file mode 100644 index 00000000..1dbe46ff --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/local-v-model/crud.jsx @@ -0,0 +1,32 @@ +import { uiContext } from "@fast-crud/fast-crud"; + +export default function ({ expose }) { + return { + crudOptions: { + mode:{ + name:'local', + isMergeWhenUpdate:true, + isAppendWhenAdd:true + }, + search: { + show: false + }, + toolbar:{ + show:false, + }, + pagination:{ + show:false + }, + columns: { + name: { + type: "text", + title: "联系人姓名" + }, + mobile: { + type: "text", + title: "联系人手机号码" + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/local-v-model/index.vue b/packages/ui/certd-client/src/views/crud/feature/local-v-model/index.vue new file mode 100644 index 00000000..01e615f5 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/local-v-model/index.vue @@ -0,0 +1,51 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/local-v-model/local.vue b/packages/ui/certd-client/src/views/crud/feature/local-v-model/local.vue new file mode 100644 index 00000000..0110ae27 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/local-v-model/local.vue @@ -0,0 +1,67 @@ + + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/local/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/local/crud.jsx new file mode 100644 index 00000000..c0f2f6af --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/local/crud.jsx @@ -0,0 +1,35 @@ +import { uiContext } from "@fast-crud/fast-crud"; + +export default function ({ expose }) { + return { + crudOptions: { + mode: { + name: "local", + isMergeWhenUpdate: true, + isAppendWhenAdd: true + }, + actionbar: { buttons: { add: { show: true }, addRow: { show: false } } }, + editable: { + enabled: false, + mode: "row", + activeTrigger: false + }, + search: { + show: false + }, + pagination: { + show: false + }, + columns: { + name: { + type: "text", + title: "联系人姓名" + }, + mobile: { + type: "text", + title: "联系人手机号码" + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/local/index.vue b/packages/ui/certd-client/src/views/crud/feature/local/index.vue new file mode 100644 index 00000000..743588f1 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/local/index.vue @@ -0,0 +1,89 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/merge/api.js b/packages/ui/certd-client/src/views/crud/feature/merge/api.js new file mode 100644 index 00000000..65dafffc --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/merge/api.js @@ -0,0 +1,43 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FeatureMerge"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} + diff --git a/packages/ui/certd-client/src/views/crud/feature/merge/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/merge/crud.jsx new file mode 100644 index 00000000..36d41897 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/merge/crud.jsx @@ -0,0 +1,129 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + /** + * 列合并render + */ + function colMergeRender({ index }) { + return { + props: { + colSpan: 5 + } + }; + } + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + table: { + slots: { + summary() { + return
总结栏
; + } + } + }, + columns: { + id: { + title: "id", + type: "text" + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + }, + cellMerge: { + title: "上下合并", + column: { + customRender: ({ text, index }, cellRender) => { + const obj = { + props: {} + }; + if (index === 2) { + obj.children = text + "(我合并了)"; + obj.props.rowSpan = 2; + } else if (index === 3) { + obj.props.rowSpan = 0; + } else { + obj.children = cellRender(); + } + return obj; + } + } + }, + colMerge1: { + title: "左右合并", + column: { + align: "center", + customRender({ text, index, record, dataIndex }, cellRender) { + if (index !== 4) { + return { + children: cellRender() + }; + } + return { + children: text + "(我合并了)", + props: { + colSpan: 2 + } + }; + } + } + }, + colMerge2: { + title: "左右合并", + column: { + customRender({ text, index, record, dataIndex }, cellRender) { + if (index !== 4) { + return { + children: cellRender() + }; + } + return { + props: { + colSpan: 0 + } + }; + } + } + }, + header1: { + title: "表头合并(我合并了)", + type: "text", + column: { + colSpan: 2 + } + }, + header2: { + title: "表头合并", + type: "text", + column: { + colSpan: 0 + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/merge/index.vue b/packages/ui/certd-client/src/views/crud/feature/merge/index.vue new file mode 100644 index 00000000..49d0ce99 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/merge/index.vue @@ -0,0 +1,39 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/merge/mock.js b/packages/ui/certd-client/src/views/crud/feature/merge/mock.js new file mode 100644 index 00000000..e99a6af5 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/merge/mock.js @@ -0,0 +1,36 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FeatureMerge", + idGenerator: 0 +}; +const list = [ + { + radio: "1", + cellMerge: "test", + colMerge1: "111", + colMerge2: "222", + + header1: "aaa", + header2: "bbb" + }, + { + radio: "2", + cellMerge: "test", + colMerge1: "111", + colMerge2: "222", + + header1: "aaa", + header2: "bbb" + }, + { + radio: "0", + cellMerge: "test", + colMerge1: "111", + colMerge2: "222", + header1: "aaa", + header2: "bbb" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/remove/api.js b/packages/ui/certd-client/src/views/crud/feature/remove/api.js new file mode 100644 index 00000000..1d251eb7 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/remove/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FeatureRemove"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/feature/remove/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/remove/crud.jsx new file mode 100644 index 00000000..52a476cd --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/remove/crud.jsx @@ -0,0 +1,74 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +import { Modal } from "ant-design-vue"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + table: { + remove: { + async confirmFn(context) { + await new Promise((resolve, reject) => { + Modal.confirm({ + content: `确定删除记录(${context.row.id})吗?`, + onOk() { + resolve(); + }, + onCancel() { + reject(); + } + }); + }); + }, + confirmTitle: "请确认", // confirmFn配置为空时生效 + confirmMessage: "确定删除此记录吗", // confirmFn配置为空时生效 + showSuccessMessage: true, //是否显示删除成功记录 + refreshTable: true, //删除后刷新表格 + onCanceled({ row }) { + console.log(`记录${row.id}取消删除`); + }, + onRemoved({ row }) { + console.log(`记录${row.id}已删除`); + } + } + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + text: { + title: "文本", + search: { show: true }, + type: "text" + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/remove/index.vue b/packages/ui/certd-client/src/views/crud/feature/remove/index.vue new file mode 100644 index 00000000..804e85bb --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/remove/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/remove/mock.js b/packages/ui/certd-client/src/views/crud/feature/remove/mock.js new file mode 100644 index 00000000..efb116af --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/remove/mock.js @@ -0,0 +1,25 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FeatureRemove", + idGenerator: 0 +}; +const list = [ + { + text: "测试文本1" + }, + { + text: "测试文本2" + }, + { + text: "测试文本3" + }, + { + text: "测试文本4" + }, + { + text: "测试文本5" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/search-multi/api.js b/packages/ui/certd-client/src/views/crud/feature/search-multi/api.js new file mode 100644 index 00000000..2f83742a --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/search-multi/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FeatureSearchMulti"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/feature/search-multi/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/search-multi/crud.jsx new file mode 100644 index 00000000..6f9fdbd2 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/search-multi/crud.jsx @@ -0,0 +1,143 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +import { ref } from "vue"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + search: { + layout: "multi-line", + col: { + span: 4 + }, + options: { + labelCol: { + style: { + width: "100px" + } + } + } + }, + actionbar: { + buttons: { + change: { + text: "切换模式", + click() { + if (expose.crudBinding.value.search.layout === "multi-line") { + expose.crudBinding.value.search.layout = ""; + } else { + expose.crudBinding.value.search.layout = "multi-line"; + } + } + }, + search: { + text: "查询", + click() { + expose.getSearchRef().doSearch(); + } + }, + reset: { + text: "重置查询", + click() { + expose.getSearchRef().doReset(); + } + } + } + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }), + column: { + filters: [ + { text: "开", value: "1" }, + { text: "关", value: "0" }, + { text: "停", value: "2" } + ], + // specify the condition of filtering result + // here is that finding the name started with `value` + onFilter: (value, record) => { + return record.radio === value; + }, + sorter: (a, b) => a.radio - b.radio, + sortDirections: ["descend"] + } + }, + text1: { + type: "text", + title: "text1", + search: { show: true } + }, + text2: { + type: "text", + title: "text2", + search: { show: true } + }, + text3: { + type: "text", + title: "text3", + search: { show: true } + }, + text4: { + type: "text", + title: "text4", + search: { show: true } + }, + text5: { + type: "text", + title: "text5", + search: { show: true } + }, + text6: { + type: "text", + title: "text6", + search: { show: true } + }, + text7: { + type: "text", + title: "text7", + search: { show: true } + }, + text8: { + type: "text", + title: "text8", + search: { show: true } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/search-multi/index.vue b/packages/ui/certd-client/src/views/crud/feature/search-multi/index.vue new file mode 100644 index 00000000..6e6d9605 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/search-multi/index.vue @@ -0,0 +1,41 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/search-multi/mock.js b/packages/ui/certd-client/src/views/crud/feature/search-multi/mock.js new file mode 100644 index 00000000..0a253152 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/search-multi/mock.js @@ -0,0 +1,19 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FeatureSearchMulti", + idGenerator: 0 +}; +const list = [ + { + radio: "1" + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/search/api.js b/packages/ui/certd-client/src/views/crud/feature/search/api.js new file mode 100644 index 00000000..279509cc --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/search/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FeatureSearch"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/feature/search/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/search/crud.jsx new file mode 100644 index 00000000..06139536 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/search/crud.jsx @@ -0,0 +1,91 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +import { ref } from "vue"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + table: { + // 表头过滤改变事件 + onFilterChange(e) { + console.log("onFilterChange", e); + } + }, + search: { + initialForm: { + radio: "0" + }, + buttons: { + custom: { + text: "自定义", + show: true, + order: 3, + icon: { + icon: "ant-design:search", + style: { + "font-size": "16px" + } + }, + click() { + console.log("点击了自定义按钮"); + } + } + } + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }), + column: { + filters: [ + { text: "开", value: "1" }, + { text: "关", value: "0" }, + { text: "停", value: "2" } + ], + // specify the condition of filtering result + // here is that finding the name started with `value` + onFilter: (value, record) => { + return record.radio === value; + }, + sorter: (a, b) => a.radio - b.radio, + sortDirections: ["descend"] + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/search/index.vue b/packages/ui/certd-client/src/views/crud/feature/search/index.vue new file mode 100644 index 00000000..e36b8dff --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/search/index.vue @@ -0,0 +1,57 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/search/mock.js b/packages/ui/certd-client/src/views/crud/feature/search/mock.js new file mode 100644 index 00000000..a6741fa0 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/search/mock.js @@ -0,0 +1,19 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FeatureSearch", + idGenerator: 0 +}; +const list = [ + { + radio: "1" + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/selection-radio/api.js b/packages/ui/certd-client/src/views/crud/feature/selection-radio/api.js new file mode 100644 index 00000000..1d86caa2 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/selection-radio/api.js @@ -0,0 +1,50 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FeatureSelection"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} + +export function BatchDelete(ids) { + return request({ + url: apiPrefix + "/batchDelete", + method: "post", + data: { ids } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/feature/selection-radio/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/selection-radio/crud.jsx new file mode 100644 index 00000000..18efb25f --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/selection-radio/crud.jsx @@ -0,0 +1,67 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +import { ref } from "vue"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + const selectedRowKey = ref(); + const onSelectChange = (changed) => { + console.log("selection", changed); + selectedRowKey.value = changed; + }; + return { + selectedRowKey, //返回给index.vue去使用 + crudOptions: { + table: { + rowKey: "id", + rowSelection: { + type: "radio", + selectedRowKeys: selectedRowKey, + onChange: onSelectChange, + getCheckboxProps: (record) => ({ + disabled: record.id === 1 // 此处演示第一行禁用 + }) + } + }, + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/selection-radio/index.vue b/packages/ui/certd-client/src/views/crud/feature/selection-radio/index.vue new file mode 100644 index 00000000..57386c5a --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/selection-radio/index.vue @@ -0,0 +1,45 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/selection-radio/mock.js b/packages/ui/certd-client/src/views/crud/feature/selection-radio/mock.js new file mode 100644 index 00000000..b9b0bade --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/selection-radio/mock.js @@ -0,0 +1,19 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FeatureSelection", + idGenerator: 0 +}; +const list = [ + { + radio: "1" + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/selection/api.js b/packages/ui/certd-client/src/views/crud/feature/selection/api.js new file mode 100644 index 00000000..1d86caa2 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/selection/api.js @@ -0,0 +1,50 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FeatureSelection"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} + +export function BatchDelete(ids) { + return request({ + url: apiPrefix + "/batchDelete", + method: "post", + data: { ids } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/feature/selection/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/selection/crud.jsx new file mode 100644 index 00000000..9ac917e3 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/selection/crud.jsx @@ -0,0 +1,67 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +import { ref } from "vue"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + const selectedRowKeys = ref([]); + + const onSelectChange = (changed) => { + console.log("selection", changed); + selectedRowKeys.value = changed; + }; + return { + selectedRowKeys, //返回给index.vue去使用 + crudOptions: { + table: { + rowKey: "id", + rowSelection: { + selectedRowKeys: selectedRowKeys, + onChange: onSelectChange, + getCheckboxProps: (record) => ({ + disabled: record.id === 1 // 此处演示第一行禁用 + }) + } + }, + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/selection/index.vue b/packages/ui/certd-client/src/views/crud/feature/selection/index.vue new file mode 100644 index 00000000..7a84d6c2 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/selection/index.vue @@ -0,0 +1,68 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/selection/mock.js b/packages/ui/certd-client/src/views/crud/feature/selection/mock.js new file mode 100644 index 00000000..b9b0bade --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/selection/mock.js @@ -0,0 +1,19 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FeatureSelection", + idGenerator: 0 +}; +const list = [ + { + radio: "1" + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/sortable/api.js b/packages/ui/certd-client/src/views/crud/feature/sortable/api.js new file mode 100644 index 00000000..17fe338f --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/sortable/api.js @@ -0,0 +1,50 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FeatureSortable"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} + +export function BatchDelete(ids) { + return request({ + url: apiPrefix + "/batchDelete", + method: "post", + data: { ids } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/feature/sortable/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/sortable/crud.jsx new file mode 100644 index 00000000..0b00b387 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/sortable/crud.jsx @@ -0,0 +1,62 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + return { + crudOptions: { + request: { + pageRequest: api.GetList, + addRequest, + editRequest, + delRequest + }, + columns: { + radio: { + title: "本地排序", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }), + column: { + sorter(a, b) { + return a.radio < b.radio ? 1 : -1; + } + } + }, + radio1: { + title: "服务端排序1", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }), + column: { + sorter: true + } + }, + radio2: { + title: "服务端排序2", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }), + column: { + sorter: true + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/sortable/index.vue b/packages/ui/certd-client/src/views/crud/feature/sortable/index.vue new file mode 100644 index 00000000..1d3e5945 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/sortable/index.vue @@ -0,0 +1,39 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/sortable/mock.js b/packages/ui/certd-client/src/views/crud/feature/sortable/mock.js new file mode 100644 index 00000000..5bb6d0e6 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/sortable/mock.js @@ -0,0 +1,25 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FeatureSortable", + idGenerator: 0 +}; +const list = [ + { + radio: "1", + radio1: "1", + radio2: "2" + }, + { + radio: "2", + radio1: "2", + radio2: "0" + }, + { + radio: "0", + radio1: "0", + radio2: "1" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/tree/api.js b/packages/ui/certd-client/src/views/crud/feature/tree/api.js new file mode 100644 index 00000000..77163398 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/tree/api.js @@ -0,0 +1,50 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FeatureTree"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} + +export function BatchDelete(ids) { + return request({ + url: apiPrefix + "/batchDelete", + method: "post", + data: { ids } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/feature/tree/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/tree/crud.jsx new file mode 100644 index 00000000..b47c3fa9 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/tree/crud.jsx @@ -0,0 +1,91 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +import { ref } from "vue"; + +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + const selectedRowKeys = ref([]); + + const onSelectChange = (changed) => { + console.log("selection", changed); + selectedRowKeys.value = changed; + }; + return { + selectedRowKeys, //返回给index.vue去使用 + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + table: { + rowSelection: { selectedRowKeys: selectedRowKeys, onChange: onSelectChange } + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 100 + }, + form: { + show: false + } + }, + time: { + title: "时间", + type: "datetime", + column: { + width: 180 + } + }, + province: { + title: "地区", + type: "dict-select", + search: { show: true }, + form: { + component: { filterable: true, multiple: true } + }, + dict: dict({ + data: [ + { value: "sz", label: "深圳" }, + { value: "gz", label: "广州" }, + { value: "wh", label: "武汉" }, + { value: "sh", label: "上海" } + ] + }), + column: { + width: 300 + } + }, + amount: { + title: "金额(元)", + key: "amount" + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/tree/index.vue b/packages/ui/certd-client/src/views/crud/feature/tree/index.vue new file mode 100644 index 00000000..b9240eac --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/tree/index.vue @@ -0,0 +1,65 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/tree/mock.js b/packages/ui/certd-client/src/views/crud/feature/tree/mock.js new file mode 100644 index 00000000..f1df3bad --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/tree/mock.js @@ -0,0 +1,85 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FeatureTree", + idGenerator: 0 +}; +const list = [ + { + radio: "1", + data: "我会懒加载", + time: "2020-01-01 11:11:11", + province: "wh", + amount: 100, + hasChildren: true, + loaded: false, + children: [ + { + data: "懒加载的子数据", + province: ["sh", "gz"], + time: "2020-01-01 11:11:11", + amount: 100 + }, + { + data: "懒加载的子数据2", + province: ["sh", "sz"], + time: "2020-01-01 11:11:11", + amount: 100 + } + ] + }, + { + data: "data2", + province: "sh", + time: "2020-01-01 11:11:11", + amount: 100, + children: [ + { + id: 999, + data: "data1_1", + time: "2020-01-01 11:11:11", + province: ["gz", "sz"], // 可以逗号分隔的字符串 'gz,sz' + amount: 100, + children: [ + { + id: 1000, + data: "data1_1_1", + time: "2020-01-01 11:11:11", + province: ["sz", "gz"], // 可以逗号分隔的字符串 'gz,sz' + amount: 100 + } + ] + }, + { + id: 888, + data: "data1_2", + time: "2020-01-01 11:11:11", + province: "sh", + amount: 100, + children: [ + { + id: 889, + data: "data1_2_1", + time: "2020-01-01 11:11:11", + province: "gz", + amount: 100 + } + ] + } + ] + }, + { + data: "data3", + province: ["sh", "gz"], + time: "2020-01-01 11:11:11", + amount: 100 + }, + { + data: "data4", + province: ["sh", "sz"], + time: "2020-01-01 11:11:11", + amount: 100 + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/feature/value-builder/api.js b/packages/ui/certd-client/src/views/crud/feature/value-builder/api.js new file mode 100644 index 00000000..09e547c6 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/value-builder/api.js @@ -0,0 +1,50 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FeatureValueBuilder"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} + +export function BatchDelete(ids) { + return request({ + url: apiPrefix + "/batchDelete", + method: "post", + data: { ids } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/feature/value-builder/crud.jsx b/packages/ui/certd-client/src/views/crud/feature/value-builder/crud.jsx new file mode 100644 index 00000000..b44f2483 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/value-builder/crud.jsx @@ -0,0 +1,54 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + return { + crudOptions: { + request: { + pageRequest: api.GetList, + addRequest, + editRequest, + delRequest + }, + columns: { + name: { + title: "姓名", + type: "text" + }, + roles: { + title: "角色", + search: { show: true }, + type: "dict-select", + dict: dict({ + value: "id", + label: "name", + data: [ + { id: 1, name: "管理员" }, + { id: 2, name: "普通用户" } + ] + }), + form: { + component: { + mode: "multiple" + }, + valueBuilder({ form }) { + if (form.roles) { + form.roles = form.roles.map((item) => item.id); + } + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/feature/value-builder/index.vue b/packages/ui/certd-client/src/views/crud/feature/value-builder/index.vue new file mode 100644 index 00000000..156b4e5b --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/value-builder/index.vue @@ -0,0 +1,46 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/feature/value-builder/mock.js b/packages/ui/certd-client/src/views/crud/feature/value-builder/mock.js new file mode 100644 index 00000000..8c86a37e --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/feature/value-builder/mock.js @@ -0,0 +1,21 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "FeatureValueBuilder", + idGenerator: 0 +}; +const list = [ + { + name: "user1", + roles: [ + { id: 1, name: "管理员" }, + { id: 2, name: "普通用户" } + ] + }, + { + name: "user2", + roles: [{ id: 1, name: "管理员" }] + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/form/base/api.js b/packages/ui/certd-client/src/views/crud/form/base/api.js new file mode 100644 index 00000000..cff9ab91 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/base/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FormBase"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/form/base/crud.jsx b/packages/ui/certd-client/src/views/crud/form/base/crud.jsx new file mode 100644 index 00000000..26220cee --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/base/crud.jsx @@ -0,0 +1,55 @@ +import * as api from "./api"; +export default function ({ crudExpose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + form: { + wrapper: { + buttons: { + ok: { + text: "保存" + } + } + } + }, + columns: { + name: { + title: "姓名", + type: "text" + }, + renderLabel: { + title: "labelRender", + type: "text", + form: { + title(context) { + console.log("render label context:", context); + return
LabelRender
; + }, + helper: { + text: "配置form.title为一个render方法即可自定义label" + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/form/base/index.vue b/packages/ui/certd-client/src/views/crud/form/base/index.vue new file mode 100644 index 00000000..c7a2168c --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/base/index.vue @@ -0,0 +1,31 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/form/base/mock.js b/packages/ui/certd-client/src/views/crud/form/base/mock.js new file mode 100644 index 00000000..bb0fe7b9 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/base/mock.js @@ -0,0 +1,310 @@ +import mockUtil from "/src/mock/base"; + +const options = { + name: "FormBase", + idGenerator: 0 +}; +const list = [ + { + name: "王小虎", + age: 15, + password: "", + status: "2", + url: "https://baidu.com" + }, + { + name: "张三", + age: 18, + password: "", + url: "https://baidu.com" + }, + { + status: "2" + } +]; + +const dictData = [ + { + value: "zhinan", + label: "指南", + children: [ + { + value: "shejiyuanze", + label: "设计原则", + children: [ + { + value: "yizhi", + label: "一致" + }, + { + value: "fankui", + label: "反馈" + }, + { + value: "xiaolv", + label: "效率" + }, + { + value: "kekong", + label: "可控" + } + ] + }, + { + value: "daohang", + label: "导航", + children: [ + { + value: "cexiangdaohang", + label: "侧向导航" + }, + { + value: "dingbudaohang", + label: "顶部导航" + } + ] + } + ] + }, + { + value: "zujian", + label: "组件", + children: [ + { + value: "basic", + label: "Basic", + children: [ + { + value: "layout", + label: "Layout 布局" + }, + { + value: "color", + label: "Color 色彩" + }, + { + value: "typography", + label: "Typography 字体" + }, + { + value: "icon", + label: "Icon 图标" + }, + { + value: "button", + label: "Button 按钮" + } + ] + }, + { + value: "form", + label: "Form", + children: [ + { + value: "radio", + label: "Radio 单选框" + }, + { + value: "checkbox", + label: "Checkbox 多选框" + }, + { + value: "input", + label: "Input 输入框" + }, + { + value: "input-number", + label: "InputNumber 计数器" + }, + { + value: "select", + label: "Select 选择器" + }, + { + value: "cascader", + label: "Cascader 级联选择器" + }, + { + value: "switch", + label: "Switch 开关" + }, + { + value: "slider", + label: "Slider 滑块" + }, + { + value: "time-picker", + label: "TimePicker 时间选择器" + }, + { + value: "date-picker", + label: "DatePicker 日期选择器" + }, + { + value: "datetime-picker", + label: "DateTimePicker 日期时间选择器" + }, + { + value: "upload", + label: "Upload 上传" + }, + { + value: "rate", + label: "Rate 评分" + }, + { + value: "form", + label: "Form 表单" + } + ] + }, + { + value: "data", + label: "Data", + children: [ + { + value: "table", + label: "Table 表格" + }, + { + value: "tag", + label: "Tag 标签" + }, + { + value: "progress", + label: "Progress 进度条" + }, + { + value: "tree", + label: "Tree 树形控件" + }, + { + value: "pagination", + label: "Pagination 分页" + }, + { + value: "badge", + label: "Badge 标记" + } + ] + }, + { + value: "notice", + label: "Notice", + children: [ + { + value: "alert", + label: "Alert 警告" + }, + { + value: "loading", + label: "Loading 加载" + }, + { + value: "message", + label: "Message 消息提示" + }, + { + value: "message-box", + label: "MessageBox 弹框" + }, + { + value: "notification", + label: "Notification 通知" + } + ] + }, + { + value: "navigation", + label: "Navigation", + children: [ + { + value: "menu", + label: "NavMenu 导航菜单" + }, + { + value: "tabs", + label: "Tabs 标签页" + }, + { + value: "breadcrumb", + label: "Breadcrumb 面包屑" + }, + { + value: "dropdown", + label: "Dropdown 下拉菜单" + }, + { + value: "steps", + label: "Steps 步骤条" + } + ] + }, + { + value: "others", + label: "Others", + children: [ + { + value: "dialog", + label: "Dialog 对话框" + }, + { + value: "tooltip", + label: "Tooltip 文字提示" + }, + { + value: "popover", + label: "Popover 弹出框" + }, + { + value: "card", + label: "Card 卡片" + }, + { + value: "carousel", + label: "Carousel 走马灯" + }, + { + value: "collapse", + label: "Collapse 折叠面板" + } + ] + } + ] + }, + { + value: "ziyuan", + label: "资源", + children: [ + { + value: "axure", + label: "Axure Components" + }, + { + value: "sketch", + label: "Sketch Templates" + }, + { + value: "jiaohu", + label: "组件交互文档" + } + ] + } +]; + +options.list = list; +options.copyTimes = 1000; +const mock = mockUtil.buildMock(options); +mock.push({ + path: "/select/cascadeData", + method: "get", + handle(req) { + return { + code: 0, + msg: "success", + data: dictData + }; + } +}); + +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/form/custom-form/api.js b/packages/ui/certd-client/src/views/crud/form/custom-form/api.js new file mode 100644 index 00000000..1cab3602 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/custom-form/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FormCustomForm"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/form/custom-form/crud.jsx b/packages/ui/certd-client/src/views/crud/form/custom-form/crud.jsx new file mode 100644 index 00000000..875a8063 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/custom-form/crud.jsx @@ -0,0 +1,40 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const { getFormRef, getFormData } = expose; + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + title: { + title: "商品标题", + type: "text" + }, + code: { + title: "商品代码", + search: { show: true }, + type: "text" + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/form/custom-form/index.vue b/packages/ui/certd-client/src/views/crud/form/custom-form/index.vue new file mode 100644 index 00000000..faa3c2be --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/custom-form/index.vue @@ -0,0 +1,86 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/form/custom-form/mock.js b/packages/ui/certd-client/src/views/crud/form/custom-form/mock.js new file mode 100644 index 00000000..479b89b4 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/custom-form/mock.js @@ -0,0 +1,303 @@ +import mockUtil from "/src/mock/base"; + +const options = { + name: "FormCustomForm", + idGenerator: 0 +}; +const list = [ + { + title: "无线充电宝", + code: "100001", + images: "https://img0.bdstatic.com/static/searchdetail/img/logo-2X_0c4ef02.png", + price: 100, + stock: 99, + intro: "30000毫安超大容量移动电源充电宝官方原装正品专用便携", + content: "" + } +]; + +const dictData = [ + { + value: "zhinan", + label: "指南", + children: [ + { + value: "shejiyuanze", + label: "设计原则", + children: [ + { + value: "yizhi", + label: "一致" + }, + { + value: "fankui", + label: "反馈" + }, + { + value: "xiaolv", + label: "效率" + }, + { + value: "kekong", + label: "可控" + } + ] + }, + { + value: "daohang", + label: "导航", + children: [ + { + value: "cexiangdaohang", + label: "侧向导航" + }, + { + value: "dingbudaohang", + label: "顶部导航" + } + ] + } + ] + }, + { + value: "zujian", + label: "组件", + children: [ + { + value: "basic", + label: "Basic", + children: [ + { + value: "layout", + label: "Layout 布局" + }, + { + value: "color", + label: "Color 色彩" + }, + { + value: "typography", + label: "Typography 字体" + }, + { + value: "icon", + label: "Icon 图标" + }, + { + value: "button", + label: "Button 按钮" + } + ] + }, + { + value: "form", + label: "Form", + children: [ + { + value: "radio", + label: "Radio 单选框" + }, + { + value: "checkbox", + label: "Checkbox 多选框" + }, + { + value: "input", + label: "Input 输入框" + }, + { + value: "input-number", + label: "InputNumber 计数器" + }, + { + value: "select", + label: "Select 选择器" + }, + { + value: "cascader", + label: "Cascader 级联选择器" + }, + { + value: "switch", + label: "Switch 开关" + }, + { + value: "slider", + label: "Slider 滑块" + }, + { + value: "time-picker", + label: "TimePicker 时间选择器" + }, + { + value: "date-picker", + label: "DatePicker 日期选择器" + }, + { + value: "datetime-picker", + label: "DateTimePicker 日期时间选择器" + }, + { + value: "upload", + label: "Upload 上传" + }, + { + value: "rate", + label: "Rate 评分" + }, + { + value: "form", + label: "Form 表单" + } + ] + }, + { + value: "data", + label: "Data", + children: [ + { + value: "table", + label: "Table 表格" + }, + { + value: "tag", + label: "Tag 标签" + }, + { + value: "progress", + label: "Progress 进度条" + }, + { + value: "tree", + label: "Tree 树形控件" + }, + { + value: "pagination", + label: "Pagination 分页" + }, + { + value: "badge", + label: "Badge 标记" + } + ] + }, + { + value: "notice", + label: "Notice", + children: [ + { + value: "alert", + label: "Alert 警告" + }, + { + value: "loading", + label: "Loading 加载" + }, + { + value: "message", + label: "Message 消息提示" + }, + { + value: "message-box", + label: "MessageBox 弹框" + }, + { + value: "notification", + label: "Notification 通知" + } + ] + }, + { + value: "navigation", + label: "Navigation", + children: [ + { + value: "menu", + label: "NavMenu 导航菜单" + }, + { + value: "tabs", + label: "Tabs 标签页" + }, + { + value: "breadcrumb", + label: "Breadcrumb 面包屑" + }, + { + value: "dropdown", + label: "Dropdown 下拉菜单" + }, + { + value: "steps", + label: "Steps 步骤条" + } + ] + }, + { + value: "others", + label: "Others", + children: [ + { + value: "dialog", + label: "Dialog 对话框" + }, + { + value: "tooltip", + label: "Tooltip 文字提示" + }, + { + value: "popover", + label: "Popover 弹出框" + }, + { + value: "card", + label: "Card 卡片" + }, + { + value: "carousel", + label: "Carousel 走马灯" + }, + { + value: "collapse", + label: "Collapse 折叠面板" + } + ] + } + ] + }, + { + value: "ziyuan", + label: "资源", + children: [ + { + value: "axure", + label: "Axure Components" + }, + { + value: "sketch", + label: "Sketch Templates" + }, + { + value: "jiaohu", + label: "组件交互文档" + } + ] + } +]; + +options.list = list; +options.copyTimes = 1000; +const mock = mockUtil.buildMock(options); +mock.push({ + path: "/select/cascadeData", + method: "get", + handle(req) { + return { + code: 0, + msg: "success", + data: dictData + }; + } +}); + +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/form/drawer/api.js b/packages/ui/certd-client/src/views/crud/form/drawer/api.js new file mode 100644 index 00000000..b9e50dc6 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/drawer/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/formText"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/form/drawer/crud.jsx b/packages/ui/certd-client/src/views/crud/form/drawer/crud.jsx new file mode 100644 index 00000000..bf6e0c5f --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/drawer/crud.jsx @@ -0,0 +1,44 @@ +import * as api from "./api"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + form: { + wrapper: { + is: "a-drawer" + } + }, + columns: { + name: { + title: "姓名", + type: "text", //虽然不写也能正确显示组件,但不建议省略它 + search: { show: true }, + form: { + component: { + maxlength: 20 + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/form/drawer/index.vue b/packages/ui/certd-client/src/views/crud/form/drawer/index.vue new file mode 100644 index 00000000..5143f074 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/drawer/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/form/drawer/mock.js b/packages/ui/certd-client/src/views/crud/form/drawer/mock.js new file mode 100644 index 00000000..fcf01621 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/drawer/mock.js @@ -0,0 +1,40 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "formText", + idGenerator: 0 +}; +const list = [ + { + name: "王小虎", + date: "2016-05-02", + status: "0", + province: "1", + avatar: "https://alicdn.antdv.com/vue.png", + show: true, + city: "sz", + address: "123123", + zip: "518000", + intro: "王小虎是element-plus的table示例出现的名字" + }, + { + name: "张三", + date: "2016-05-04", + status: "1", + province: "2" + }, + { + name: "李四", + date: 2232433534511, + status: "1", + province: "0" + }, + { + name: "王五", + date: "2016-05-03", + status: "2", + province: "wh,gz" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/form/group-tabs/api.js b/packages/ui/certd-client/src/views/crud/form/group-tabs/api.js new file mode 100644 index 00000000..a059b900 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/group-tabs/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FormGroupTabs"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/form/group-tabs/crud.jsx b/packages/ui/certd-client/src/views/crud/form/group-tabs/crud.jsx new file mode 100644 index 00000000..74dbfb0b --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/group-tabs/crud.jsx @@ -0,0 +1,114 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const { getFormRef, getFormData } = expose; + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + title: { + title: "商品标题", + type: "text" + }, + code: { + title: "商品代码", + search: { show: true }, + type: "text", + form: { + rules: [{ required: true, message: "此项必填" }] + } + }, + images: { + title: "图片", + type: "image-uploader" + }, + price: { + title: "价格", + sortable: true + }, + store: { + title: "库存", + type: "number" + }, + intro: { + title: "简介", + type: "textarea", + column: { + ellipsis: true, + showTitle: true + } + }, + content: { + title: "详情", + type: "editor-ueditor", + form: { + labelWidth: "0px" + } + } + }, + form: { + group: { + groupType: "tabs", //collapse, tabs + accordion: false, + groups: { + base: { + slots: { + tab: (scope) => { + return ( + + + 商品基础 + + ); + } + }, + icon: "el-icon-goods", + columns: ["code", "title", "images"] + }, + price: { + tab: "库存价格", + icon: "el-icon-price-tag", + columns: ["store", "price"] + }, + info: { + tab: "详情", + collapsed: true, //默认折叠 + icon: "el-icon-warning-outline", + columns: ["intro", "content"] + } + // custom: { + // title: "自定义", + // collapsed: false, + // show(context) { + // console.log("custom context", context); + // return context.mode === "view"; + // }, + // disabled: false, + // icon: "el-icon-warning-outline", + // columns: ["custom", "custom2"] + // } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/form/group-tabs/index.vue b/packages/ui/certd-client/src/views/crud/form/group-tabs/index.vue new file mode 100644 index 00000000..3d65edec --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/group-tabs/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/form/group-tabs/mock.js b/packages/ui/certd-client/src/views/crud/form/group-tabs/mock.js new file mode 100644 index 00000000..bc980fa8 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/group-tabs/mock.js @@ -0,0 +1,303 @@ +import mockUtil from "/src/mock/base"; + +const options = { + name: "FormGroupTabs", + idGenerator: 0 +}; +const list = [ + { + title: "无线充电宝", + code: "100001", + images: "https://img0.bdstatic.com/static/searchdetail/img/logo-2X_0c4ef02.png", + price: 100, + stock: 99, + intro: "30000毫安超大容量移动电源充电宝官方原装正品专用便携", + content: "" + } +]; + +const dictData = [ + { + value: "zhinan", + label: "指南", + children: [ + { + value: "shejiyuanze", + label: "设计原则", + children: [ + { + value: "yizhi", + label: "一致" + }, + { + value: "fankui", + label: "反馈" + }, + { + value: "xiaolv", + label: "效率" + }, + { + value: "kekong", + label: "可控" + } + ] + }, + { + value: "daohang", + label: "导航", + children: [ + { + value: "cexiangdaohang", + label: "侧向导航" + }, + { + value: "dingbudaohang", + label: "顶部导航" + } + ] + } + ] + }, + { + value: "zujian", + label: "组件", + children: [ + { + value: "basic", + label: "Basic", + children: [ + { + value: "layout", + label: "Layout 布局" + }, + { + value: "color", + label: "Color 色彩" + }, + { + value: "typography", + label: "Typography 字体" + }, + { + value: "icon", + label: "Icon 图标" + }, + { + value: "button", + label: "Button 按钮" + } + ] + }, + { + value: "form", + label: "Form", + children: [ + { + value: "radio", + label: "Radio 单选框" + }, + { + value: "checkbox", + label: "Checkbox 多选框" + }, + { + value: "input", + label: "Input 输入框" + }, + { + value: "input-number", + label: "InputNumber 计数器" + }, + { + value: "select", + label: "Select 选择器" + }, + { + value: "cascader", + label: "Cascader 级联选择器" + }, + { + value: "switch", + label: "Switch 开关" + }, + { + value: "slider", + label: "Slider 滑块" + }, + { + value: "time-picker", + label: "TimePicker 时间选择器" + }, + { + value: "date-picker", + label: "DatePicker 日期选择器" + }, + { + value: "datetime-picker", + label: "DateTimePicker 日期时间选择器" + }, + { + value: "upload", + label: "Upload 上传" + }, + { + value: "rate", + label: "Rate 评分" + }, + { + value: "form", + label: "Form 表单" + } + ] + }, + { + value: "data", + label: "Data", + children: [ + { + value: "table", + label: "Table 表格" + }, + { + value: "tag", + label: "Tag 标签" + }, + { + value: "progress", + label: "Progress 进度条" + }, + { + value: "tree", + label: "Tree 树形控件" + }, + { + value: "pagination", + label: "Pagination 分页" + }, + { + value: "badge", + label: "Badge 标记" + } + ] + }, + { + value: "notice", + label: "Notice", + children: [ + { + value: "alert", + label: "Alert 警告" + }, + { + value: "loading", + label: "Loading 加载" + }, + { + value: "message", + label: "Message 消息提示" + }, + { + value: "message-box", + label: "MessageBox 弹框" + }, + { + value: "notification", + label: "Notification 通知" + } + ] + }, + { + value: "navigation", + label: "Navigation", + children: [ + { + value: "menu", + label: "NavMenu 导航菜单" + }, + { + value: "tabs", + label: "Tabs 标签页" + }, + { + value: "breadcrumb", + label: "Breadcrumb 面包屑" + }, + { + value: "dropdown", + label: "Dropdown 下拉菜单" + }, + { + value: "steps", + label: "Steps 步骤条" + } + ] + }, + { + value: "others", + label: "Others", + children: [ + { + value: "dialog", + label: "Dialog 对话框" + }, + { + value: "tooltip", + label: "Tooltip 文字提示" + }, + { + value: "popover", + label: "Popover 弹出框" + }, + { + value: "card", + label: "Card 卡片" + }, + { + value: "carousel", + label: "Carousel 走马灯" + }, + { + value: "collapse", + label: "Collapse 折叠面板" + } + ] + } + ] + }, + { + value: "ziyuan", + label: "资源", + children: [ + { + value: "axure", + label: "Axure Components" + }, + { + value: "sketch", + label: "Sketch Templates" + }, + { + value: "jiaohu", + label: "组件交互文档" + } + ] + } +]; + +options.list = list; +options.copyTimes = 1000; +const mock = mockUtil.buildMock(options); +mock.push({ + path: "/select/cascadeData", + method: "get", + handle(req) { + return { + code: 0, + msg: "success", + data: dictData + }; + } +}); + +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/form/group/api.js b/packages/ui/certd-client/src/views/crud/form/group/api.js new file mode 100644 index 00000000..b1fcf856 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/group/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FormGroup"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/form/group/crud.jsx b/packages/ui/certd-client/src/views/crud/form/group/crud.jsx new file mode 100644 index 00000000..8016d35e --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/group/crud.jsx @@ -0,0 +1,143 @@ +import * as api from "./api"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + title: { + title: "商品标题", + type: "text" + }, + code: { + title: "商品代码", + search: { show: true }, + type: "text" + }, + images: { + title: "图片", + type: "image-uploader" + }, + price: { + title: "价格", + sortable: true + }, + store: { + title: "库存", + type: "number" + }, + intro: { + title: "简介", + type: "textarea", + column: { + ellipsis: true, + showTitle: true + } + }, + content: { + title: "详情", + type: "editor-ueditor", + form: { + labelWidth: "0px" + } + }, + slotField: { + title: "插槽示例", + type: "text" + }, + product: { + title: "未分组字段", + type: "text", + form: { + col: { span: 24 }, + helper: "未分组的字段会显示在这里,一般来说你应该把所有字段都编入分组内" + } + }, + hidden1: { + title: "隐藏1", + type: "text", + form: { + show: false + }, + column: { + show: false + } + }, + hidden2: { + title: "隐藏2", + type: "text", + form: { + show: false + }, + column: { + show: false + } + } + }, + form: { + group: { + type: "collapse", // tab + accordion: true, //手风琴模式 + groups: { + base: { + slots: { + //自定义header + header: () => { + return ( + + 商品基础 + + + ); + } + }, + columns: ["code", "title", "images", "invalidKey"] + }, + price: { + header: "库存价格", + columns: ["store", "price"] + }, + info: { + header: "详情", + collapsed: true, //默认折叠 + columns: ["intro", "content", "slotField"] + }, + hiddenTest: { + header: "分组隐藏测试", //如果组里面的所有的组件都配置了隐藏,则本分组隐藏 + columns: ["hidden1", "hidden2"] + } + // custom: { + // title: "自定义", + // collapsed: false, + // show(context) { + // console.log("custom context", context); + // return context.mode === "view"; + // }, + // disabled: false, + // icon: "el-icon-warning-outline", + // columns: ["custom", "custom2"] + // } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/form/group/index.vue b/packages/ui/certd-client/src/views/crud/form/group/index.vue new file mode 100644 index 00000000..14e290c7 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/group/index.vue @@ -0,0 +1,46 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/form/group/mock.js b/packages/ui/certd-client/src/views/crud/form/group/mock.js new file mode 100644 index 00000000..70d8f4d4 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/group/mock.js @@ -0,0 +1,303 @@ +import mockUtil from "/src/mock/base"; + +const options = { + name: "FormGroup", + idGenerator: 0 +}; +const list = [ + { + title: "无线充电宝", + code: "100001", + images: "https://img0.bdstatic.com/static/searchdetail/img/logo-2X_0c4ef02.png", + price: 100, + stock: 99, + intro: "30000毫安超大容量移动电源充电宝官方原装正品专用便携", + content: "" + } +]; + +const dictData = [ + { + value: "zhinan", + label: "指南", + children: [ + { + value: "shejiyuanze", + label: "设计原则", + children: [ + { + value: "yizhi", + label: "一致" + }, + { + value: "fankui", + label: "反馈" + }, + { + value: "xiaolv", + label: "效率" + }, + { + value: "kekong", + label: "可控" + } + ] + }, + { + value: "daohang", + label: "导航", + children: [ + { + value: "cexiangdaohang", + label: "侧向导航" + }, + { + value: "dingbudaohang", + label: "顶部导航" + } + ] + } + ] + }, + { + value: "zujian", + label: "组件", + children: [ + { + value: "basic", + label: "Basic", + children: [ + { + value: "layout", + label: "Layout 布局" + }, + { + value: "color", + label: "Color 色彩" + }, + { + value: "typography", + label: "Typography 字体" + }, + { + value: "icon", + label: "Icon 图标" + }, + { + value: "button", + label: "Button 按钮" + } + ] + }, + { + value: "form", + label: "Form", + children: [ + { + value: "radio", + label: "Radio 单选框" + }, + { + value: "checkbox", + label: "Checkbox 多选框" + }, + { + value: "input", + label: "Input 输入框" + }, + { + value: "input-number", + label: "InputNumber 计数器" + }, + { + value: "select", + label: "Select 选择器" + }, + { + value: "cascader", + label: "Cascader 级联选择器" + }, + { + value: "switch", + label: "Switch 开关" + }, + { + value: "slider", + label: "Slider 滑块" + }, + { + value: "time-picker", + label: "TimePicker 时间选择器" + }, + { + value: "date-picker", + label: "DatePicker 日期选择器" + }, + { + value: "datetime-picker", + label: "DateTimePicker 日期时间选择器" + }, + { + value: "upload", + label: "Upload 上传" + }, + { + value: "rate", + label: "Rate 评分" + }, + { + value: "form", + label: "Form 表单" + } + ] + }, + { + value: "data", + label: "Data", + children: [ + { + value: "table", + label: "Table 表格" + }, + { + value: "tag", + label: "Tag 标签" + }, + { + value: "progress", + label: "Progress 进度条" + }, + { + value: "tree", + label: "Tree 树形控件" + }, + { + value: "pagination", + label: "Pagination 分页" + }, + { + value: "badge", + label: "Badge 标记" + } + ] + }, + { + value: "notice", + label: "Notice", + children: [ + { + value: "alert", + label: "Alert 警告" + }, + { + value: "loading", + label: "Loading 加载" + }, + { + value: "message", + label: "Message 消息提示" + }, + { + value: "message-box", + label: "MessageBox 弹框" + }, + { + value: "notification", + label: "Notification 通知" + } + ] + }, + { + value: "navigation", + label: "Navigation", + children: [ + { + value: "menu", + label: "NavMenu 导航菜单" + }, + { + value: "tabs", + label: "Tabs 标签页" + }, + { + value: "breadcrumb", + label: "Breadcrumb 面包屑" + }, + { + value: "dropdown", + label: "Dropdown 下拉菜单" + }, + { + value: "steps", + label: "Steps 步骤条" + } + ] + }, + { + value: "others", + label: "Others", + children: [ + { + value: "dialog", + label: "Dialog 对话框" + }, + { + value: "tooltip", + label: "Tooltip 文字提示" + }, + { + value: "popover", + label: "Popover 弹出框" + }, + { + value: "card", + label: "Card 卡片" + }, + { + value: "carousel", + label: "Carousel 走马灯" + }, + { + value: "collapse", + label: "Collapse 折叠面板" + } + ] + } + ] + }, + { + value: "ziyuan", + label: "资源", + children: [ + { + value: "axure", + label: "Axure Components" + }, + { + value: "sketch", + label: "Sketch Templates" + }, + { + value: "jiaohu", + label: "组件交互文档" + } + ] + } +]; + +options.list = list; +options.copyTimes = 1000; +const mock = mockUtil.buildMock(options); +mock.push({ + path: "/select/cascadeData", + method: "get", + handle(req) { + return { + code: 0, + msg: "success", + data: dictData + }; + } +}); + +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/form/helper/api.js b/packages/ui/certd-client/src/views/crud/form/helper/api.js new file mode 100644 index 00000000..aa8f0890 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/helper/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FormHelper"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/form/helper/crud.jsx b/packages/ui/certd-client/src/views/crud/form/helper/crud.jsx new file mode 100644 index 00000000..e9946e84 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/helper/crud.jsx @@ -0,0 +1,72 @@ +import * as api from "./api"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + form: { + labelCol: { span: 6 }, + wrapperCol: { span: 16 }, + helper: { + // position: "label" // helper的展示位置全局配置 + // tooltip:{} + } + }, + columns: { + name: { + title: "最简单", + type: "text", + form: { + helper: "最简单的helper\n换行测试" + } + }, + age: { + title: "jsx", + type: "text", + form: { + helper: { + render() { + return
jsx自定义render
; + } + } + } + }, + status: { + title: "显示在label", + type: "text", + form: { + rules: [{ required: true, message: "此项必填" }], + helper: { + position: "label", + tooltip: { + placement: "topLeft" + }, + text: "在label通过tooltip方式显示的helper\n换行测试" + // render() { + // return
在label通过tooltip方式显示的helper
; + // } + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/form/helper/index.vue b/packages/ui/certd-client/src/views/crud/form/helper/index.vue new file mode 100644 index 00000000..44057448 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/helper/index.vue @@ -0,0 +1,48 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/form/helper/mock.js b/packages/ui/certd-client/src/views/crud/form/helper/mock.js new file mode 100644 index 00000000..92b3daca --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/helper/mock.js @@ -0,0 +1,310 @@ +import mockUtil from "/src/mock/base"; + +const options = { + name: "FormHelper", + idGenerator: 0 +}; +const list = [ + { + name: "王小虎", + age: 15, + password: "", + status: "2", + url: "https://baidu.com" + }, + { + name: "张三", + age: 18, + password: "", + url: "https://baidu.com" + }, + { + status: "2" + } +]; + +const dictData = [ + { + value: "zhinan", + label: "指南", + children: [ + { + value: "shejiyuanze", + label: "设计原则", + children: [ + { + value: "yizhi", + label: "一致" + }, + { + value: "fankui", + label: "反馈" + }, + { + value: "xiaolv", + label: "效率" + }, + { + value: "kekong", + label: "可控" + } + ] + }, + { + value: "daohang", + label: "导航", + children: [ + { + value: "cexiangdaohang", + label: "侧向导航" + }, + { + value: "dingbudaohang", + label: "顶部导航" + } + ] + } + ] + }, + { + value: "zujian", + label: "组件", + children: [ + { + value: "basic", + label: "Basic", + children: [ + { + value: "layout", + label: "Layout 布局" + }, + { + value: "color", + label: "Color 色彩" + }, + { + value: "typography", + label: "Typography 字体" + }, + { + value: "icon", + label: "Icon 图标" + }, + { + value: "button", + label: "Button 按钮" + } + ] + }, + { + value: "form", + label: "Form", + children: [ + { + value: "radio", + label: "Radio 单选框" + }, + { + value: "checkbox", + label: "Checkbox 多选框" + }, + { + value: "input", + label: "Input 输入框" + }, + { + value: "input-number", + label: "InputNumber 计数器" + }, + { + value: "select", + label: "Select 选择器" + }, + { + value: "cascader", + label: "Cascader 级联选择器" + }, + { + value: "switch", + label: "Switch 开关" + }, + { + value: "slider", + label: "Slider 滑块" + }, + { + value: "time-picker", + label: "TimePicker 时间选择器" + }, + { + value: "date-picker", + label: "DatePicker 日期选择器" + }, + { + value: "datetime-picker", + label: "DateTimePicker 日期时间选择器" + }, + { + value: "upload", + label: "Upload 上传" + }, + { + value: "rate", + label: "Rate 评分" + }, + { + value: "form", + label: "Form 表单" + } + ] + }, + { + value: "data", + label: "Data", + children: [ + { + value: "table", + label: "Table 表格" + }, + { + value: "tag", + label: "Tag 标签" + }, + { + value: "progress", + label: "Progress 进度条" + }, + { + value: "tree", + label: "Tree 树形控件" + }, + { + value: "pagination", + label: "Pagination 分页" + }, + { + value: "badge", + label: "Badge 标记" + } + ] + }, + { + value: "notice", + label: "Notice", + children: [ + { + value: "alert", + label: "Alert 警告" + }, + { + value: "loading", + label: "Loading 加载" + }, + { + value: "message", + label: "Message 消息提示" + }, + { + value: "message-box", + label: "MessageBox 弹框" + }, + { + value: "notification", + label: "Notification 通知" + } + ] + }, + { + value: "navigation", + label: "Navigation", + children: [ + { + value: "menu", + label: "NavMenu 导航菜单" + }, + { + value: "tabs", + label: "Tabs 标签页" + }, + { + value: "breadcrumb", + label: "Breadcrumb 面包屑" + }, + { + value: "dropdown", + label: "Dropdown 下拉菜单" + }, + { + value: "steps", + label: "Steps 步骤条" + } + ] + }, + { + value: "others", + label: "Others", + children: [ + { + value: "dialog", + label: "Dialog 对话框" + }, + { + value: "tooltip", + label: "Tooltip 文字提示" + }, + { + value: "popover", + label: "Popover 弹出框" + }, + { + value: "card", + label: "Card 卡片" + }, + { + value: "carousel", + label: "Carousel 走马灯" + }, + { + value: "collapse", + label: "Collapse 折叠面板" + } + ] + } + ] + }, + { + value: "ziyuan", + label: "资源", + children: [ + { + value: "axure", + label: "Axure Components" + }, + { + value: "sketch", + label: "Sketch Templates" + }, + { + value: "jiaohu", + label: "组件交互文档" + } + ] + } +]; + +options.list = list; +options.copyTimes = 1000; +const mock = mockUtil.buildMock(options); +mock.push({ + path: "/select/cascadeData", + method: "get", + handle(req) { + return { + code: 0, + msg: "success", + data: dictData + }; + } +}); + +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/form/independent/crud.jsx b/packages/ui/certd-client/src/views/crud/form/independent/crud.jsx new file mode 100644 index 00000000..7e492d64 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/independent/crud.jsx @@ -0,0 +1,59 @@ +export default function ({ expose }) { + return { + crudOptions: { + form: { + wrapper: { + onClosed(e) { + console.log("onClosed", e); + }, + onOpened(e) { + console.log("onOpened", e); + } + }, + labelCol: { span: 6 }, + wrapperCol: { span: 16 }, + helper: { + // position: "label" // helper的展示位置全局配置 + // tooltip:{} + } + }, + columns: { + name: { + title: "最简单", + type: "text", + form: { + helper: "最简单的helper" + } + }, + age: { + title: "jsx", + type: "text", + form: { + helper: { + render() { + return
jsx自定义render
; + } + } + } + }, + status: { + title: "显示在label", + type: "text", + form: { + rules: [{ required: true, message: "此项必填" }], + helper: { + position: "label", + tooltip: { + placement: "topLeft" + }, + text: "在label通过tooltip方式显示的helper" + // render() { + // return
在label通过tooltip方式显示的helper
; + // } + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/form/independent/index.vue b/packages/ui/certd-client/src/views/crud/form/independent/index.vue new file mode 100644 index 00000000..63390444 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/independent/index.vue @@ -0,0 +1,215 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/form/inner/api.js b/packages/ui/certd-client/src/views/crud/form/inner/api.js new file mode 100644 index 00000000..d8c3543c --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/inner/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FormInner"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/form/inner/area/api.js b/packages/ui/certd-client/src/views/crud/form/inner/area/api.js new file mode 100644 index 00000000..b9142c89 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/inner/area/api.js @@ -0,0 +1,50 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FormInnerArea"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function GetAll(query) { + return request({ + url: apiPrefix + "/all", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/form/inner/area/crud.jsx b/packages/ui/certd-client/src/views/crud/form/inner/area/crud.jsx new file mode 100644 index 00000000..dbd13b80 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/inner/area/crud.jsx @@ -0,0 +1,39 @@ +import * as api from "./api"; +import { dict, useExpose } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + form: { + wrapper: { + inner: true + } + }, + columns: { + area: { + title: "地区", + type: "text" + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/form/inner/area/index.vue b/packages/ui/certd-client/src/views/crud/form/inner/area/index.vue new file mode 100644 index 00000000..ab81c09b --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/inner/area/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/form/inner/area/mock.js b/packages/ui/certd-client/src/views/crud/form/inner/area/mock.js new file mode 100644 index 00000000..d7c076ef --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/inner/area/mock.js @@ -0,0 +1,24 @@ +import mockUtil from "/src/mock/base"; + +const options = { + name: "FormInnerArea", + idGenerator: 0 +}; +const list = [ + { + area: "深圳" + }, + { + area: "北京" + }, + { + area: "上海" + }, + { + area: "广州" + } +]; +options.list = list; +options.copyTimes = 1; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/form/inner/crud.jsx b/packages/ui/certd-client/src/views/crud/form/inner/crud.jsx new file mode 100644 index 00000000..c7009bf7 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/inner/crud.jsx @@ -0,0 +1,77 @@ +import * as api from "./api"; +import { dict, useExpose } from "@fast-crud/fast-crud"; +import { useRouter } from "vue-router"; +import { message } from "ant-design-vue"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + const router = useRouter(); + const areaDict = dict({ + value: "id", + label: "area", + url: "/mock/FormInnerArea/all" + }); + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + form: { + wrapper: { + inner: true + } + }, + columns: { + name: { + title: "姓名", + type: "text" + }, + age: { + title: "年龄", + type: "text" + }, + area: { + title: "地区", + type: "dict-select", + dict: areaDict, + form: { + suffixRender() { + function refresh() { + message.info("刷新dict"); + areaDict.reloadDict(); + } + function gotoAddArea() { + message.info("调用 router.push 打开地区管理页面"); + router.push({ path: "/crud/form/inner/area" }); + } + return ( + + + + + 添加地区 + + ); + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/form/inner/index.vue b/packages/ui/certd-client/src/views/crud/form/inner/index.vue new file mode 100644 index 00000000..ab81c09b --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/inner/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/form/inner/mock.js b/packages/ui/certd-client/src/views/crud/form/inner/mock.js new file mode 100644 index 00000000..a9f809c8 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/inner/mock.js @@ -0,0 +1,25 @@ +import mockUtil from "/src/mock/base"; + +const options = { + name: "FormInner", + idGenerator: 0 +}; +const list = [ + { + name: "王小虎", + age: 15, + password: "", + status: "2", + url: "https://baidu.com" + }, + { + name: "张三", + age: 18, + password: "", + url: "https://baidu.com" + } +]; +options.list = list; +options.copyTimes = 1000; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/form/layout-flex/api.js b/packages/ui/certd-client/src/views/crud/form/layout-flex/api.js new file mode 100644 index 00000000..0ba39afe --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/layout-flex/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/formLayoutFlex"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/form/layout-flex/crud.jsx b/packages/ui/certd-client/src/views/crud/form/layout-flex/crud.jsx new file mode 100644 index 00000000..1e7c5c38 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/layout-flex/crud.jsx @@ -0,0 +1,63 @@ +import * as api from "./api"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + form: { + display: "flex", + labelCol: { + //固定label宽度 + span: null, + style: { + width: "120px" + } + }, + wrapperCol: { + span: null + } + }, + columns: { + name: { + title: "姓名", + type: "text", + search: { show: true } + }, + order: { + title: "字段排序", + type: "text", + form: { + order: 0 + } + }, + intro: { + title: "跨列", + search: { show: true }, + type: ["textarea"], + form: { + col: { span: 24 } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/form/layout-flex/index.vue b/packages/ui/certd-client/src/views/crud/form/layout-flex/index.vue new file mode 100644 index 00000000..e43bc8cf --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/layout-flex/index.vue @@ -0,0 +1,43 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/form/layout-flex/mock.js b/packages/ui/certd-client/src/views/crud/form/layout-flex/mock.js new file mode 100644 index 00000000..e48c1f0f --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/layout-flex/mock.js @@ -0,0 +1,35 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "formLayoutFlex", + idGenerator: 0 +}; +const list = [ + { + name: "王小虎", + date: "2016-05-02", + status: "0", + province: "1", + avatar: "https://alicdn.antdv.com/vue.png", + show: true, + city: "sz", + address: "123123", + zip: "518000", + order: "我在编辑的时候会排到第一个", + intro: "王小虎是element-plus的table示例出现的名字" + }, + { + name: "张三", + date: "2016-05-04", + status: "1", + province: "2" + }, + { + name: "李四", + date: 2232433534511, + status: "1", + province: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/form/layout-grid/api.js b/packages/ui/certd-client/src/views/crud/form/layout-grid/api.js new file mode 100644 index 00000000..c00a5787 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/layout-grid/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/formLayoutGrid"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/form/layout-grid/crud.jsx b/packages/ui/certd-client/src/views/crud/form/layout-grid/crud.jsx new file mode 100644 index 00000000..284f7b9f --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/layout-grid/crud.jsx @@ -0,0 +1,67 @@ +import * as api from "./api"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + form: { + // 具体可配置请参考 grid 布局: http://www.ruanyifeng.com/blog/2019/03/grid-layout-tutorial.html + display: "grid" + }, + columns: { + avatar: { + title: "头像上传", + type: "avatar-uploader", + form: { + order: 0, + col: { + style: { gridRow: "span 3" } + }, + helper: "通过grid布局,可以实现比flex更加规整的排列" + } + }, + name: { + title: "姓名", + type: "text", + search: { show: true } + }, + order: { + title: "占位演示", + type: "text" + }, + place: { + title: "占位演示", + type: "text" + }, + intro: { + title: "跨列", + type: "textarea", + form: { + col: { + style: { gridColumn: "span 2" } // grid 模式控制跨列 + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/form/layout-grid/index.vue b/packages/ui/certd-client/src/views/crud/form/layout-grid/index.vue new file mode 100644 index 00000000..499e5fe7 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/layout-grid/index.vue @@ -0,0 +1,52 @@ + + + + diff --git a/packages/ui/certd-client/src/views/crud/form/layout-grid/mock.js b/packages/ui/certd-client/src/views/crud/form/layout-grid/mock.js new file mode 100644 index 00000000..41ec7888 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/layout-grid/mock.js @@ -0,0 +1,34 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "formLayoutGrid", + idGenerator: 0 +}; +const list = [ + { + name: "王小虎", + date: "2016-05-02", + status: "0", + province: "1", + avatar: "https://alicdn.antdv.com/vue.png", + show: true, + city: "sz", + address: "123123", + zip: "518000", + order: "我在编辑的时候会排到第一个", + intro: "王小虎是element-plus的table示例出现的名字" + }, + { + name: "张三", + date: "2016-05-04", + status: "1" + }, + { + name: "李四", + date: 2232433534511, + status: "1", + province: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/form/layout/api.js b/packages/ui/certd-client/src/views/crud/form/layout/api.js new file mode 100644 index 00000000..d9a78941 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/layout/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/formLayout"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/form/layout/crud.jsx b/packages/ui/certd-client/src/views/crud/form/layout/crud.jsx new file mode 100644 index 00000000..fabaec8e --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/layout/crud.jsx @@ -0,0 +1,101 @@ +import * as api from "./api"; +import { dict, compute } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + + const { getFormData, getFormWrapperRef } = expose; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + form: { + /** + * flex模式,通过 + * grid模式 + */ + display: "flex", + wrapper: { + customClass: "page-layout", + onOpened(context) { + getFormWrapperRef().formOptions.display = context.options.initial?.display; + console.log("form opened", context, getFormData()); + } + } + }, + columns: { + display: { + title: "布局", + type: "dict-radio", + dict: dict({ + data: [ + { value: "flex", label: "flex", color: "blue" }, + { value: "grid", label: "grid", color: "green" } + ] + }), + search: { show: true, valueChange: null }, + form: { + valueChange(context) { + const { value } = context; + getFormWrapperRef().formOptions.display = value; + console.log("valueChange", value, context); + } + } + }, + name: { + title: "姓名", + type: "text", + search: { show: true } + }, + zip: { + title: "邮编", + type: "text" + }, + blank: { + title: "表单占位栏", + type: "text", + form: { + blank: true + } + }, + gridSpan: { + title: "grid跨列", + type: "textarea", + form: { + col: { + style: { gridColumn: "span 2" } // grid 模式 + } + } + }, + flexSpan: { + title: "flex跨列", + type: "textarea", + search: { show: false }, + form: { + show: compute((context) => { + // grid跨列模式下使用flex模式的设置会显示异常,为了演示效果,在grid模式下隐藏 + return context.form.display !== "grid"; + }), + col: { span: 24 } // flex模式跨列配置 + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/form/layout/index.vue b/packages/ui/certd-client/src/views/crud/form/layout/index.vue new file mode 100644 index 00000000..1a969b41 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/layout/index.vue @@ -0,0 +1,50 @@ + + + + diff --git a/packages/ui/certd-client/src/views/crud/form/layout/mock.js b/packages/ui/certd-client/src/views/crud/form/layout/mock.js new file mode 100644 index 00000000..f63208a5 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/layout/mock.js @@ -0,0 +1,41 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "formLayout", + idGenerator: 0 +}; +const list = [ + { + display: "flex", + name: "aa", + date: "2016-05-02", + status: "0", + province: "1", + avatar: "https://alicdn.antdv.com/vue.png", + show: true, + city: "sz", + address: "123123", + zip: "518000" + }, + { + display: "grid", + name: "bb", + date: "2016-05-04", + status: "1", + province: "2" + }, + { + name: "cc", + date: 2232433534511, + status: "1", + province: "0" + }, + { + name: "dd", + date: "2016-05-03", + status: "2", + province: "wh,gz" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/form/nest/api.js b/packages/ui/certd-client/src/views/crud/form/nest/api.js new file mode 100644 index 00000000..f7d01faa --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/nest/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FormNestObject"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/form/nest/crud.jsx b/packages/ui/certd-client/src/views/crud/form/nest/crud.jsx new file mode 100644 index 00000000..1bf0a55a --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/nest/crud.jsx @@ -0,0 +1,76 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + form: { + labelCol: { span: 6 }, + wrapperCol: { span: 16 }, + helper: { + // position: "label" // helper的展示位置全局配置 + // tooltip:{} + } + }, + columns: { + username: { + title: "用户名", + type: "text" + }, + "profile.name": { + title: "profile.name", + type: "text", + search:{show:true}, + form: { + key: ["profile", "name"], + rules: [{ required: true, message: "姓名必填" }] + } + }, + "profile.age": { + title: "profile.age", + type: "number", + form: { + key: ["profile", "age"] + } + }, + "profile.status": { + title: "profile.status", + type: "dict-select", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }), + form: { + key: ["profile", "status"] + } + }, + "profile.count": { + title: "不提交的字段", + type: "text", + form: { + submit: false, + key: ["profile", "count"] + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/form/nest/index.vue b/packages/ui/certd-client/src/views/crud/form/nest/index.vue new file mode 100644 index 00000000..5e4c48c9 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/nest/index.vue @@ -0,0 +1,48 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/form/nest/mock.js b/packages/ui/certd-client/src/views/crud/form/nest/mock.js new file mode 100644 index 00000000..1658d74a --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/nest/mock.js @@ -0,0 +1,319 @@ +import mockUtil from "/src/mock/base"; + +const options = { + name: "FormNestObject", + idGenerator: 0 +}; +const list = [ + { + username: "wangxiaohu", + profile: { + name: "王小虎", + age: 15, + status: "1", + count: "配置submit=false将不会提交给后台" + } + }, + { + username: "zhangsan", + profile: { + name: "张三", + age: 18, + status: "2" + } + }, + { + username: "lisi", + profile: { + name: "李四", + age: 18, + status: "2" + } + } +]; + +const dictData = [ + { + value: "zhinan", + label: "指南", + children: [ + { + value: "shejiyuanze", + label: "设计原则", + children: [ + { + value: "yizhi", + label: "一致" + }, + { + value: "fankui", + label: "反馈" + }, + { + value: "xiaolv", + label: "效率" + }, + { + value: "kekong", + label: "可控" + } + ] + }, + { + value: "daohang", + label: "导航", + children: [ + { + value: "cexiangdaohang", + label: "侧向导航" + }, + { + value: "dingbudaohang", + label: "顶部导航" + } + ] + } + ] + }, + { + value: "zujian", + label: "组件", + children: [ + { + value: "basic", + label: "Basic", + children: [ + { + value: "layout", + label: "Layout 布局" + }, + { + value: "color", + label: "Color 色彩" + }, + { + value: "typography", + label: "Typography 字体" + }, + { + value: "icon", + label: "Icon 图标" + }, + { + value: "button", + label: "Button 按钮" + } + ] + }, + { + value: "form", + label: "Form", + children: [ + { + value: "radio", + label: "Radio 单选框" + }, + { + value: "checkbox", + label: "Checkbox 多选框" + }, + { + value: "input", + label: "Input 输入框" + }, + { + value: "input-number", + label: "InputNumber 计数器" + }, + { + value: "select", + label: "Select 选择器" + }, + { + value: "cascader", + label: "Cascader 级联选择器" + }, + { + value: "switch", + label: "Switch 开关" + }, + { + value: "slider", + label: "Slider 滑块" + }, + { + value: "time-picker", + label: "TimePicker 时间选择器" + }, + { + value: "date-picker", + label: "DatePicker 日期选择器" + }, + { + value: "datetime-picker", + label: "DateTimePicker 日期时间选择器" + }, + { + value: "upload", + label: "Upload 上传" + }, + { + value: "rate", + label: "Rate 评分" + }, + { + value: "form", + label: "Form 表单" + } + ] + }, + { + value: "data", + label: "Data", + children: [ + { + value: "table", + label: "Table 表格" + }, + { + value: "tag", + label: "Tag 标签" + }, + { + value: "progress", + label: "Progress 进度条" + }, + { + value: "tree", + label: "Tree 树形控件" + }, + { + value: "pagination", + label: "Pagination 分页" + }, + { + value: "badge", + label: "Badge 标记" + } + ] + }, + { + value: "notice", + label: "Notice", + children: [ + { + value: "alert", + label: "Alert 警告" + }, + { + value: "loading", + label: "Loading 加载" + }, + { + value: "message", + label: "Message 消息提示" + }, + { + value: "message-box", + label: "MessageBox 弹框" + }, + { + value: "notification", + label: "Notification 通知" + } + ] + }, + { + value: "navigation", + label: "Navigation", + children: [ + { + value: "menu", + label: "NavMenu 导航菜单" + }, + { + value: "tabs", + label: "Tabs 标签页" + }, + { + value: "breadcrumb", + label: "Breadcrumb 面包屑" + }, + { + value: "dropdown", + label: "Dropdown 下拉菜单" + }, + { + value: "steps", + label: "Steps 步骤条" + } + ] + }, + { + value: "others", + label: "Others", + children: [ + { + value: "dialog", + label: "Dialog 对话框" + }, + { + value: "tooltip", + label: "Tooltip 文字提示" + }, + { + value: "popover", + label: "Popover 弹出框" + }, + { + value: "card", + label: "Card 卡片" + }, + { + value: "carousel", + label: "Carousel 走马灯" + }, + { + value: "collapse", + label: "Collapse 折叠面板" + } + ] + } + ] + }, + { + value: "ziyuan", + label: "资源", + children: [ + { + value: "axure", + label: "Axure Components" + }, + { + value: "sketch", + label: "Sketch Templates" + }, + { + value: "jiaohu", + label: "组件交互文档" + } + ] + } +]; + +options.list = list; +options.copyTimes = 1000; +const mock = mockUtil.buildMock(options); +mock.push({ + path: "/select/cascadeData", + method: "get", + handle(req) { + return { + code: 0, + msg: "success", + data: dictData + }; + } +}); + +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/form/new-page/api.js b/packages/ui/certd-client/src/views/crud/form/new-page/api.js new file mode 100644 index 00000000..0dc2616a --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/new-page/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FormNewPage"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/get", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/form/new-page/crud.jsx b/packages/ui/certd-client/src/views/crud/form/new-page/crud.jsx new file mode 100644 index 00000000..c6828281 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/new-page/crud.jsx @@ -0,0 +1,96 @@ +import * as api from "./api"; +import { useRouter } from "vue-router"; +export default function ({ expose }) { + const router = useRouter(); + + const { getFormRef, getFormData } = expose; + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + if (row.id) { + form.id = row.id; + } + + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + actionbar: { + buttons: { + add: { + click() { + router.push("/crud/form/new-page/edit"); + } + } + } + }, + rowHandle: { + buttons: { + edit: { + click(context) { + router.push("/crud/form/new-page/edit?id=" + context.row.id); + } + } + } + }, + columns: { + title: { + title: "商品标题", + type: "text" + }, + code: { + title: "商品代码", + search: { show: true }, + type: "text" + }, + images: { + title: "图片", + type: "image-uploader" + }, + price: { + title: "价格", + sortable: true + }, + store: { + title: "库存", + type: "number" + }, + intro: { + title: "简介", + type: "textarea", + column: { + ellipsis: true + } + }, + content: { + title: "详情", + type: ["editor-wang", "colspan"], + form: { + itemProps: { labelWidth: "0px" } + } + }, + product: { + title: "未分组字段", + type: ["text", "colspan"], + form: { + helper: "未分组的字段会显示在这里,一般来说你应该把所有字段都编入分组内" + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/form/new-page/edit.vue b/packages/ui/certd-client/src/views/crud/form/new-page/edit.vue new file mode 100644 index 00000000..c93ef0bd --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/new-page/edit.vue @@ -0,0 +1,81 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/form/new-page/index.vue b/packages/ui/certd-client/src/views/crud/form/new-page/index.vue new file mode 100644 index 00000000..0702f08c --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/new-page/index.vue @@ -0,0 +1,43 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/form/new-page/mock.js b/packages/ui/certd-client/src/views/crud/form/new-page/mock.js new file mode 100644 index 00000000..a182214c --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/new-page/mock.js @@ -0,0 +1,22 @@ +import mockUtil from "/src/mock/base"; + +const options = { + name: "FormNewPage", + idGenerator: 0 +}; +const list = [ + { + title: "无线充电宝", + code: "100001", + images: "https://img0.bdstatic.com/static/searchdetail/img/logo-2X_0c4ef02.png", + price: 100, + stock: 99, + intro: "30000毫安超大容量移动电源充电宝官方原装正品专用便携", + content: "" + } +]; + +options.list = list; +options.copyTimes = 1000; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/form/reset/api.js b/packages/ui/certd-client/src/views/crud/form/reset/api.js new file mode 100644 index 00000000..52a5ff5b --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/reset/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/formReset"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/form/reset/crud.jsx b/packages/ui/certd-client/src/views/crud/form/reset/crud.jsx new file mode 100644 index 00000000..1a4f1df2 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/reset/crud.jsx @@ -0,0 +1,56 @@ +import * as api from "./api"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + form: { + async doReset() { + console.log("reset之后可以执行其他操作"); + }, + wrapper: { + buttons: { + reset: { + text: "重置", + order: -1, + click(value) { + console.log("on reset", value); + expose.getFormRef().reset(); + } + } + } + } + }, + columns: { + name: { + title: "姓名", + type: "text", //虽然不写也能正确显示组件,但不建议省略它 + search: { show: true }, + form: { + component: { + maxlength: 20 + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/form/reset/index.vue b/packages/ui/certd-client/src/views/crud/form/reset/index.vue new file mode 100644 index 00000000..8c2e77e6 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/reset/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/form/reset/mock.js b/packages/ui/certd-client/src/views/crud/form/reset/mock.js new file mode 100644 index 00000000..f586e9c4 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/reset/mock.js @@ -0,0 +1,40 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "formReset", + idGenerator: 0 +}; +const list = [ + { + name: "王小虎", + date: "2016-05-02", + status: "0", + province: "1", + avatar: "https://alicdn.antdv.com/vue.png", + show: true, + city: "sz", + address: "123123", + zip: "518000", + intro: "王小虎是element-plus的table示例出现的名字" + }, + { + name: "张三", + date: "2016-05-04", + status: "1", + province: "2" + }, + { + name: "李四", + date: 2232433534511, + status: "1", + province: "0" + }, + { + name: "王五", + date: "2016-05-03", + status: "2", + province: "wh,gz" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/form/single-column/api.js b/packages/ui/certd-client/src/views/crud/form/single-column/api.js new file mode 100644 index 00000000..0ba49b67 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/single-column/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FormSingleColumn"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/form/single-column/crud.jsx b/packages/ui/certd-client/src/views/crud/form/single-column/crud.jsx new file mode 100644 index 00000000..f82ff917 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/single-column/crud.jsx @@ -0,0 +1,59 @@ +import * as api from "./api"; +export default function ({ crudExpose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + form: { + col: { + span: 24 + } + }, + columns: { + name: { + title: "姓名", + type: "text" + }, + title: { + title: "商品标题", + type: "text" + }, + code: { + title: "商品代码", + search: { show: true }, + type: "text" + }, + images: { + title: "图片", + type: "image-uploader" + }, + price: { + title: "价格", + sortable: true + }, + store: { + title: "库存", + type: "number" + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/form/single-column/index.vue b/packages/ui/certd-client/src/views/crud/form/single-column/index.vue new file mode 100644 index 00000000..83d27934 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/single-column/index.vue @@ -0,0 +1,31 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/form/single-column/mock.js b/packages/ui/certd-client/src/views/crud/form/single-column/mock.js new file mode 100644 index 00000000..9b37c9e7 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/single-column/mock.js @@ -0,0 +1,310 @@ +import mockUtil from "/src/mock/base"; + +const options = { + name: "FormSingleColumn", + idGenerator: 0 +}; +const list = [ + { + name: "王小虎", + age: 15, + password: "", + status: "2", + url: "https://baidu.com" + }, + { + name: "张三", + age: 18, + password: "", + url: "https://baidu.com" + }, + { + status: "2" + } +]; + +const dictData = [ + { + value: "zhinan", + label: "指南", + children: [ + { + value: "shejiyuanze", + label: "设计原则", + children: [ + { + value: "yizhi", + label: "一致" + }, + { + value: "fankui", + label: "反馈" + }, + { + value: "xiaolv", + label: "效率" + }, + { + value: "kekong", + label: "可控" + } + ] + }, + { + value: "daohang", + label: "导航", + children: [ + { + value: "cexiangdaohang", + label: "侧向导航" + }, + { + value: "dingbudaohang", + label: "顶部导航" + } + ] + } + ] + }, + { + value: "zujian", + label: "组件", + children: [ + { + value: "basic", + label: "Basic", + children: [ + { + value: "layout", + label: "Layout 布局" + }, + { + value: "color", + label: "Color 色彩" + }, + { + value: "typography", + label: "Typography 字体" + }, + { + value: "icon", + label: "Icon 图标" + }, + { + value: "button", + label: "Button 按钮" + } + ] + }, + { + value: "form", + label: "Form", + children: [ + { + value: "radio", + label: "Radio 单选框" + }, + { + value: "checkbox", + label: "Checkbox 多选框" + }, + { + value: "input", + label: "Input 输入框" + }, + { + value: "input-number", + label: "InputNumber 计数器" + }, + { + value: "select", + label: "Select 选择器" + }, + { + value: "cascader", + label: "Cascader 级联选择器" + }, + { + value: "switch", + label: "Switch 开关" + }, + { + value: "slider", + label: "Slider 滑块" + }, + { + value: "time-picker", + label: "TimePicker 时间选择器" + }, + { + value: "date-picker", + label: "DatePicker 日期选择器" + }, + { + value: "datetime-picker", + label: "DateTimePicker 日期时间选择器" + }, + { + value: "upload", + label: "Upload 上传" + }, + { + value: "rate", + label: "Rate 评分" + }, + { + value: "form", + label: "Form 表单" + } + ] + }, + { + value: "data", + label: "Data", + children: [ + { + value: "table", + label: "Table 表格" + }, + { + value: "tag", + label: "Tag 标签" + }, + { + value: "progress", + label: "Progress 进度条" + }, + { + value: "tree", + label: "Tree 树形控件" + }, + { + value: "pagination", + label: "Pagination 分页" + }, + { + value: "badge", + label: "Badge 标记" + } + ] + }, + { + value: "notice", + label: "Notice", + children: [ + { + value: "alert", + label: "Alert 警告" + }, + { + value: "loading", + label: "Loading 加载" + }, + { + value: "message", + label: "Message 消息提示" + }, + { + value: "message-box", + label: "MessageBox 弹框" + }, + { + value: "notification", + label: "Notification 通知" + } + ] + }, + { + value: "navigation", + label: "Navigation", + children: [ + { + value: "menu", + label: "NavMenu 导航菜单" + }, + { + value: "tabs", + label: "Tabs 标签页" + }, + { + value: "breadcrumb", + label: "Breadcrumb 面包屑" + }, + { + value: "dropdown", + label: "Dropdown 下拉菜单" + }, + { + value: "steps", + label: "Steps 步骤条" + } + ] + }, + { + value: "others", + label: "Others", + children: [ + { + value: "dialog", + label: "Dialog 对话框" + }, + { + value: "tooltip", + label: "Tooltip 文字提示" + }, + { + value: "popover", + label: "Popover 弹出框" + }, + { + value: "card", + label: "Card 卡片" + }, + { + value: "carousel", + label: "Carousel 走马灯" + }, + { + value: "collapse", + label: "Collapse 折叠面板" + } + ] + } + ] + }, + { + value: "ziyuan", + label: "资源", + children: [ + { + value: "axure", + label: "Axure Components" + }, + { + value: "sketch", + label: "Sketch Templates" + }, + { + value: "jiaohu", + label: "组件交互文档" + } + ] + } +]; + +options.list = list; +options.copyTimes = 1000; +const mock = mockUtil.buildMock(options); +mock.push({ + path: "/select/cascadeData", + method: "get", + handle(req) { + return { + code: 0, + msg: "success", + data: dictData + }; + } +}); + +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/form/validation/api.js b/packages/ui/certd-client/src/views/crud/form/validation/api.js new file mode 100644 index 00000000..f62ba48b --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/validation/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/FormValidation"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/form/validation/crud.jsx b/packages/ui/certd-client/src/views/crud/form/validation/crud.jsx new file mode 100644 index 00000000..856ca779 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/validation/crud.jsx @@ -0,0 +1,135 @@ +import * as api from "./api"; +import { dict, useExpose } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const { getFormRef, getFormData } = expose; + const validatePass1 = async (rule, value) => { + if (value === "") { + throw new Error("请输入密码"); + } + if (getFormData().password2 !== "") { + getFormRef().getFormRef().validateFields(["password2"]); + } + }; + const validatePass2 = async (rule, value) => { + if (value === "") { + throw new Error("请再次输入密码"); + } else if (value !== getFormData().password) { + throw new Error("两次输入密码不一致!"); + } + }; + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + form: { + row:{ + gutter:20 + }, + beforeSubmit(context) { + console.log("beforeSubmit", context); + }, + afterSubmit(context) { + console.log("afterSubmit", context); + } + }, + columns: { + name: { + title: "姓名", + type: "text", + form: { + helper: "添加和编辑时必填,编辑时额外需要校验长度", + rules: [{ required: true, message: "请输入姓名" }], + component: { + maxlength: 5, // 原生属性要写在这里 + props: { + type: "text", + showWordLimit: true + } + } + }, + editForm: { + rules: [{ min: 2, max: 5, message: "姓名长度为2-5" }] + } + }, + age: { + title: "年龄", + type: "text", + form: { + rules: [{ pattern: /^\d+$/, message: "必须为整数" }], + helper: "正则表达式" + } + }, + password: { + title: "密码", + type: "password", + column: { + component: { + cellRender() { + return ******; + } + } + }, + form: { + rules: [ + { required: true, message: "请输入密码" }, + { validator: validatePass1, trigger: "blur" } + ] + } + }, + password2: { + title: "确认密码", + type: "password", + column: { show: false }, + form: { + rules: [ + { required: true, message: "请输入确认密码" }, + { validator: validatePass2, trigger: "blur" } + ] + } + }, + status: { + title: "必选", + type: "dict-select", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum" + }), + form: { + rules: [{ required: true, message: "请选择一个选项" }] + } + }, + email: { + title: "邮箱", + type: "text", + form: { + rules: [{ type: "email", message: "请填写正确的邮箱" }] + } + }, + url: { + title: "URL", + type: "text", + form: { + rules: [{ type: "url", message: "请填写正确的url" }] + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/form/validation/index.vue b/packages/ui/certd-client/src/views/crud/form/validation/index.vue new file mode 100644 index 00000000..49bd373a --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/validation/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/form/validation/mock.js b/packages/ui/certd-client/src/views/crud/form/validation/mock.js new file mode 100644 index 00000000..0ca7bc11 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/form/validation/mock.js @@ -0,0 +1,310 @@ +import mockUtil from "/src/mock/base"; + +const options = { + name: "FormValidation", + idGenerator: 0 +}; +const list = [ + { + name: "王小虎", + age: 15, + password: "", + status: "2", + url: "https://baidu.com" + }, + { + name: "张三", + age: 18, + password: "", + url: "https://baidu.com" + }, + { + status: "2" + } +]; + +const dictData = [ + { + value: "zhinan", + label: "指南", + children: [ + { + value: "shejiyuanze", + label: "设计原则", + children: [ + { + value: "yizhi", + label: "一致" + }, + { + value: "fankui", + label: "反馈" + }, + { + value: "xiaolv", + label: "效率" + }, + { + value: "kekong", + label: "可控" + } + ] + }, + { + value: "daohang", + label: "导航", + children: [ + { + value: "cexiangdaohang", + label: "侧向导航" + }, + { + value: "dingbudaohang", + label: "顶部导航" + } + ] + } + ] + }, + { + value: "zujian", + label: "组件", + children: [ + { + value: "basic", + label: "Basic", + children: [ + { + value: "layout", + label: "Layout 布局" + }, + { + value: "color", + label: "Color 色彩" + }, + { + value: "typography", + label: "Typography 字体" + }, + { + value: "icon", + label: "Icon 图标" + }, + { + value: "button", + label: "Button 按钮" + } + ] + }, + { + value: "form", + label: "Form", + children: [ + { + value: "radio", + label: "Radio 单选框" + }, + { + value: "checkbox", + label: "Checkbox 多选框" + }, + { + value: "input", + label: "Input 输入框" + }, + { + value: "input-number", + label: "InputNumber 计数器" + }, + { + value: "select", + label: "Select 选择器" + }, + { + value: "cascader", + label: "Cascader 级联选择器" + }, + { + value: "switch", + label: "Switch 开关" + }, + { + value: "slider", + label: "Slider 滑块" + }, + { + value: "time-picker", + label: "TimePicker 时间选择器" + }, + { + value: "date-picker", + label: "DatePicker 日期选择器" + }, + { + value: "datetime-picker", + label: "DateTimePicker 日期时间选择器" + }, + { + value: "upload", + label: "Upload 上传" + }, + { + value: "rate", + label: "Rate 评分" + }, + { + value: "form", + label: "Form 表单" + } + ] + }, + { + value: "data", + label: "Data", + children: [ + { + value: "table", + label: "Table 表格" + }, + { + value: "tag", + label: "Tag 标签" + }, + { + value: "progress", + label: "Progress 进度条" + }, + { + value: "tree", + label: "Tree 树形控件" + }, + { + value: "pagination", + label: "Pagination 分页" + }, + { + value: "badge", + label: "Badge 标记" + } + ] + }, + { + value: "notice", + label: "Notice", + children: [ + { + value: "alert", + label: "Alert 警告" + }, + { + value: "loading", + label: "Loading 加载" + }, + { + value: "message", + label: "Message 消息提示" + }, + { + value: "message-box", + label: "MessageBox 弹框" + }, + { + value: "notification", + label: "Notification 通知" + } + ] + }, + { + value: "navigation", + label: "Navigation", + children: [ + { + value: "menu", + label: "NavMenu 导航菜单" + }, + { + value: "tabs", + label: "Tabs 标签页" + }, + { + value: "breadcrumb", + label: "Breadcrumb 面包屑" + }, + { + value: "dropdown", + label: "Dropdown 下拉菜单" + }, + { + value: "steps", + label: "Steps 步骤条" + } + ] + }, + { + value: "others", + label: "Others", + children: [ + { + value: "dialog", + label: "Dialog 对话框" + }, + { + value: "tooltip", + label: "Tooltip 文字提示" + }, + { + value: "popover", + label: "Popover 弹出框" + }, + { + value: "card", + label: "Card 卡片" + }, + { + value: "carousel", + label: "Carousel 走马灯" + }, + { + value: "collapse", + label: "Collapse 折叠面板" + } + ] + } + ] + }, + { + value: "ziyuan", + label: "资源", + children: [ + { + value: "axure", + label: "Axure Components" + }, + { + value: "sketch", + label: "Sketch Templates" + }, + { + value: "jiaohu", + label: "组件交互文档" + } + ] + } +]; + +options.list = list; +options.copyTimes = 1000; +const mock = mockUtil.buildMock(options); +mock.push({ + path: "/select/cascadeData", + method: "get", + handle(req) { + return { + code: 0, + msg: "success", + data: dictData + }; + } +}); + +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/home/index.vue b/packages/ui/certd-client/src/views/crud/home/index.vue new file mode 100644 index 00000000..27445779 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/home/index.vue @@ -0,0 +1,15 @@ + + + + diff --git a/packages/ui/certd-client/src/views/crud/home/page-cover/helper.js b/packages/ui/certd-client/src/views/crud/home/page-cover/helper.js new file mode 100644 index 00000000..5c955ba6 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/home/page-cover/helper.js @@ -0,0 +1,31 @@ +export default { + crud: ` columns: [ + date:{ + title: '日期', //字段名称 + type: 'date', //字段类型,添加、修改、查询将自动生成相应表单组件 + }, + status: { + title: '状态', + type: 'dict-select', //选择框,默认单选 + dict: dict({ url: '/dicts/OpenStatusEnum' })//远程数据字典 + }, + province: { + title: '地区', + type: 'dict-select', //选择框 + form: { //表单组件自定义配置,此处配置选择框为多选 + component: { //支持任何v-model组件 + filterable: true, multiple: true, clearable: true + } + }, + dict: dict({ + data: [ //本地数据字典 + { value: 'sz', label: '深圳' }, + { value: 'gz', label: '广州' }, + { value: 'wh', label: '武汉' }, + { value: 'sh', label: '上海' } + ] + }) + } + ] + ` +}; diff --git a/packages/ui/certd-client/src/views/crud/home/page-cover/image/crud.png b/packages/ui/certd-client/src/views/crud/home/page-cover/image/crud.png new file mode 100644 index 0000000000000000000000000000000000000000..3dfb047dd4cec6a1bd79e999ae8e7370af54c9c2 GIT binary patch literal 202647 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%0A-Rwf82Ui@FTb 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%0DtRsBHsTik&m(9TK{Y7Ud<)BQUrCVF4Ke>ds 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 bie&B7m4}>?q8BS}13m`lOwJaaxf=Q}FggYg literal 0 HcmV?d00001 diff --git a/packages/ui/certd-client/src/views/crud/home/page-cover/image/darkblue@2x.png b/packages/ui/certd-client/src/views/crud/home/page-cover/image/darkblue@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..efe1577f417b8aea9215372f053115d21a4b5d7a GIT binary patch literal 9259 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 O($To1UZHv~{Qm*6e(k;h literal 0 HcmV?d00001 diff --git a/packages/ui/certd-client/src/views/crud/home/page-cover/image/logo.svg b/packages/ui/certd-client/src/views/crud/home/page-cover/image/logo.svg new file mode 100644 index 00000000..7a33425e --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/home/page-cover/image/logo.svg @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ui/certd-client/src/views/crud/home/page-cover/index.vue b/packages/ui/certd-client/src/views/crud/home/page-cover/index.vue new file mode 100644 index 00000000..7c51dea3 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/home/page-cover/index.vue @@ -0,0 +1,139 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/row-handle/dropdown/api.js b/packages/ui/certd-client/src/views/crud/row-handle/dropdown/api.js new file mode 100644 index 00000000..3cfd8182 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/row-handle/dropdown/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/RowHandleDropdown"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/row-handle/dropdown/crud.jsx b/packages/ui/certd-client/src/views/crud/row-handle/dropdown/crud.jsx new file mode 100644 index 00000000..2947b537 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/row-handle/dropdown/crud.jsx @@ -0,0 +1,82 @@ +import * as api from "./api"; +import { dict, compute } from "@fast-crud/fast-crud"; +import { message } from "ant-design-vue"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + rowHandle: { + width: 290, + buttons: { + remove: { + // 根据row的值判断按钮是否显示 + show: compute(({ row }) => { + return row.radio !== "0"; + }), + dropdown: true //---------》给想要折叠的按钮配置dropdown为true,就会放入dropdown中《--------------- + }, + orderExample: { + text: "我排前面", + title: "按钮排序示例", + type: "link", + order: 0, //数字越小,越靠前,默认排序号为1 + click(opts) { + console.log("自定义操作列按钮点击", opts); + message.success("自定义操作列按钮点击"); + } + } + }, + dropdown: { + // 操作列折叠 + // 至少几个以上的按钮才会被折叠 + // atLeast: 2, //TODO 注意 [atLeast]参数即将废弃,请给button配置dropdown即可放入折叠 + more: { + text: "更多", + icon: null, + iconRight: "ion:caret-down-outline" + } + } + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/row-handle/dropdown/index.vue b/packages/ui/certd-client/src/views/crud/row-handle/dropdown/index.vue new file mode 100644 index 00000000..45d6937e --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/row-handle/dropdown/index.vue @@ -0,0 +1,40 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/row-handle/dropdown/mock.js b/packages/ui/certd-client/src/views/crud/row-handle/dropdown/mock.js new file mode 100644 index 00000000..ed703ceb --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/row-handle/dropdown/mock.js @@ -0,0 +1,19 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "RowHandleDropdown", + idGenerator: 0 +}; +const list = [ + { + radio: "1" + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/row-handle/tooltip/api.js b/packages/ui/certd-client/src/views/crud/row-handle/tooltip/api.js new file mode 100644 index 00000000..dd8bf7d8 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/row-handle/tooltip/api.js @@ -0,0 +1,50 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/RowHandleTooltip"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} + +export function BatchDelete(ids) { + return request({ + url: apiPrefix + "/batchDelete", + method: "post", + data: { ids } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/row-handle/tooltip/crud.jsx b/packages/ui/certd-client/src/views/crud/row-handle/tooltip/crud.jsx new file mode 100644 index 00000000..b8cc0141 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/row-handle/tooltip/crud.jsx @@ -0,0 +1,84 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +import { ref } from "vue"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + rowHandle: { + width: 400, + buttons: { + edit: { + tooltip: { + title: "编辑" + } + }, + view: { + tooltip: { + title: "查看" + } + }, + remove: { + tooltip: { + title: "删除" + } + }, + custom: { + text: "tooltip title render", + tooltip: { + slots: { + title() { + return ( +
+ 我是自定义render +
+ ); + } + } + } + } + } + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/row-handle/tooltip/index.vue b/packages/ui/certd-client/src/views/crud/row-handle/tooltip/index.vue new file mode 100644 index 00000000..40dde985 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/row-handle/tooltip/index.vue @@ -0,0 +1,51 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/row-handle/tooltip/mock.js b/packages/ui/certd-client/src/views/crud/row-handle/tooltip/mock.js new file mode 100644 index 00000000..7efa34b7 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/row-handle/tooltip/mock.js @@ -0,0 +1,19 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "RowHandleTooltip", + idGenerator: 0 +}; +const list = [ + { + radio: "1" + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/slots/cell/api.js b/packages/ui/certd-client/src/views/crud/slots/cell/api.js new file mode 100644 index 00000000..69094b0d --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/slots/cell/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/SlotsCell"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/slots/cell/crud.jsx b/packages/ui/certd-client/src/views/crud/slots/cell/crud.jsx new file mode 100644 index 00000000..ad836c9b --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/slots/cell/crud.jsx @@ -0,0 +1,89 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +import dayjs from "dayjs"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + const radioDict = dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }); + return { + radioDict, + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + rowHandle: { + buttons: { + edit: { dropdown: true }, + remove: { dropdown: true } + }, + width: 630 + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + like: { + title: "like", + type: "number", + search: { show: true } + }, + switch: { + title: "switch", + type: "dict-switch", + dict: dict({ + data: [ + { value: true, label: "开启" }, + { value: false, label: "关闭" } + ] + }) + }, + createDate: { + title: "时间", + type: "datetime", + column: { + align: "left", + width: 300 + }, + valueBuilder({ key, row }) { + row[key] = dayjs(row[key]); + } + }, + updateDate: { + title: "修改时间", + type: "datetime", + column: { + show: false + }, + valueBuilder({ key, row }) { + row[key] = dayjs(row[key]); + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/slots/cell/index.vue b/packages/ui/certd-client/src/views/crud/slots/cell/index.vue new file mode 100644 index 00000000..9b8b4349 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/slots/cell/index.vue @@ -0,0 +1,79 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/slots/cell/mock.js b/packages/ui/certd-client/src/views/crud/slots/cell/mock.js new file mode 100644 index 00000000..aa2397b7 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/slots/cell/mock.js @@ -0,0 +1,26 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "SlotsCell", + idGenerator: 0 +}; +const list = [ + { + like: 10000, + switch: true, + createDate: new Date().getTime(), + updateDate: new Date().getTime() + }, + { + like: 10000, + switch: false, + createDate: new Date().getTime(), + updateDate: new Date().getTime() + }, + { + like: 10000, + switch: true + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/slots/form-item/api.js b/packages/ui/certd-client/src/views/crud/slots/form-item/api.js new file mode 100644 index 00000000..924d6570 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/slots/form-item/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/SlotsFormItem"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/slots/form-item/crud.jsx b/packages/ui/certd-client/src/views/crud/slots/form-item/crud.jsx new file mode 100644 index 00000000..7af63d44 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/slots/form-item/crud.jsx @@ -0,0 +1,51 @@ +import * as api from "./api"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + topics: { + title: "多行输入", + type: "text", + search: { show: true }, + form: { + rules: [{ required: true, message: "请输入" }] + }, + column: { + component: { name: "fs-values-format" } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/slots/form-item/index.vue b/packages/ui/certd-client/src/views/crud/slots/form-item/index.vue new file mode 100644 index 00000000..97869b95 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/slots/form-item/index.vue @@ -0,0 +1,72 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/slots/form-item/mock.js b/packages/ui/certd-client/src/views/crud/slots/form-item/mock.js new file mode 100644 index 00000000..a9f3d756 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/slots/form-item/mock.js @@ -0,0 +1,13 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "SlotsFormItem", + idGenerator: 0 +}; +const list = [ + { + topics: ["fast-crud 666", "fast-crud真好用"] + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/slots/form/api.js b/packages/ui/certd-client/src/views/crud/slots/form/api.js new file mode 100644 index 00000000..b15ec4e0 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/slots/form/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/SlotsForm"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/slots/form/crud.jsx b/packages/ui/certd-client/src/views/crud/slots/form/crud.jsx new file mode 100644 index 00000000..b5d8c1df --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/slots/form/crud.jsx @@ -0,0 +1,50 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + const radioDict = dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }); + return { + radioDict, + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + text: { + title: "文本", + type: "text", + search: { show: true } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/slots/form/index.vue b/packages/ui/certd-client/src/views/crud/slots/form/index.vue new file mode 100644 index 00000000..74aa9ec3 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/slots/form/index.vue @@ -0,0 +1,69 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/slots/form/mock.js b/packages/ui/certd-client/src/views/crud/slots/form/mock.js new file mode 100644 index 00000000..22d45cf7 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/slots/form/mock.js @@ -0,0 +1,13 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "SlotsForm", + idGenerator: 0 +}; +const list = [ + { + text: "文本输入" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/slots/layout/api.js b/packages/ui/certd-client/src/views/crud/slots/layout/api.js new file mode 100644 index 00000000..56f3de45 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/slots/layout/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/SlotsLayout"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/slots/layout/crud.jsx b/packages/ui/certd-client/src/views/crud/slots/layout/crud.jsx new file mode 100644 index 00000000..af8ad45e --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/slots/layout/crud.jsx @@ -0,0 +1,49 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async (id) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/slots/layout/index.vue b/packages/ui/certd-client/src/views/crud/slots/layout/index.vue new file mode 100644 index 00000000..ce35fe28 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/slots/layout/index.vue @@ -0,0 +1,77 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/slots/layout/mock.js b/packages/ui/certd-client/src/views/crud/slots/layout/mock.js new file mode 100644 index 00000000..31e3a7d7 --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/slots/layout/mock.js @@ -0,0 +1,19 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "SlotsLayout", + idGenerator: 0 +}; +const list = [ + { + radio: "1" + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/crud/slots/search/api.js b/packages/ui/certd-client/src/views/crud/slots/search/api.js new file mode 100644 index 00000000..192ff43e --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/slots/search/api.js @@ -0,0 +1,42 @@ +import { requestForMock } from "/src/api/service"; +const request = requestForMock; +const apiPrefix = "/mock/SlotsSearch"; +export function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "get", + data: query + }); +} + +export function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "get", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/crud/slots/search/crud.jsx b/packages/ui/certd-client/src/views/crud/slots/search/crud.jsx new file mode 100644 index 00000000..af8ad45e --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/slots/search/crud.jsx @@ -0,0 +1,49 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async (id) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + columns: { + id: { + title: "ID", + key: "id", + type: "number", + column: { + width: 50 + }, + form: { + show: false + } + }, + radio: { + title: "状态", + search: { show: true }, + type: "dict-radio", + dict: dict({ + url: "/mock/dicts/OpenStatusEnum?single" + }) + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/crud/slots/search/index.vue b/packages/ui/certd-client/src/views/crud/slots/search/index.vue new file mode 100644 index 00000000..bbf30cff --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/slots/search/index.vue @@ -0,0 +1,54 @@ + + + diff --git a/packages/ui/certd-client/src/views/crud/slots/search/mock.js b/packages/ui/certd-client/src/views/crud/slots/search/mock.js new file mode 100644 index 00000000..4312767d --- /dev/null +++ b/packages/ui/certd-client/src/views/crud/slots/search/mock.js @@ -0,0 +1,19 @@ +import mockUtil from "/src/mock/base"; +const options = { + name: "SlotsSearch", + idGenerator: 0 +}; +const list = [ + { + radio: "1" + }, + { + radio: "2" + }, + { + radio: "0" + } +]; +options.list = list; +const mock = mockUtil.buildMock(options); +export default mock; diff --git a/packages/ui/certd-client/src/views/framework/error/404.vue b/packages/ui/certd-client/src/views/framework/error/404.vue new file mode 100644 index 00000000..2dacd363 --- /dev/null +++ b/packages/ui/certd-client/src/views/framework/error/404.vue @@ -0,0 +1,18 @@ + + + diff --git a/packages/ui/certd-client/src/views/framework/home/index.vue b/packages/ui/certd-client/src/views/framework/home/index.vue new file mode 100644 index 00000000..27445779 --- /dev/null +++ b/packages/ui/certd-client/src/views/framework/home/index.vue @@ -0,0 +1,15 @@ + + + + diff --git a/packages/ui/certd-client/src/views/framework/home/page-cover/helper.js b/packages/ui/certd-client/src/views/framework/home/page-cover/helper.js new file mode 100644 index 00000000..38334ac1 --- /dev/null +++ b/packages/ui/certd-client/src/views/framework/home/page-cover/helper.js @@ -0,0 +1,31 @@ +export default { + crud: ` columns: { + date:{ + title: '姓名', //字段名称 + type: 'text', //字段类型,添加、修改、查询将自动生成相应表单组件 + }, + province: { + title: '城市', + type: 'dict-select', //选择框 + form: { //表单组件自定义配置,此处配置选择框为多选 + component: { //支持任何v-model组件 + filterable: true, multiple: true, clearable: true + } + }, + dict: dict({ + data: [ //本地数据字典 + { value: 'sz', label: '深圳' }, + { value: 'gz', label: '广州' }, + { value: 'wh', label: '武汉' }, + { value: 'sh', label: '上海' } + ] + }) + }, + status: { + title: '状态', + type: 'dict-select', //选择框,默认单选 + dict: dict({ url: '/dicts/OpenStatusEnum' })//远程数据字典 + }, + } + ` +}; diff --git a/packages/ui/certd-client/src/views/framework/home/page-cover/image/crud.png b/packages/ui/certd-client/src/views/framework/home/page-cover/image/crud.png new file mode 100644 index 0000000000000000000000000000000000000000..3dfb047dd4cec6a1bd79e999ae8e7370af54c9c2 GIT binary patch literal 202647 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%0A-Rwf82Ui@FTb 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%0DtRsBHsTik&m(9TK{Y7Ud<)BQUrCVF4Ke>ds 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 bie&B7m4}>?q8BS}13m`lOwJaaxf=Q}FggYg literal 0 HcmV?d00001 diff --git a/packages/ui/certd-client/src/views/framework/home/page-cover/image/darkblue@2x.png b/packages/ui/certd-client/src/views/framework/home/page-cover/image/darkblue@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..efe1577f417b8aea9215372f053115d21a4b5d7a GIT binary patch literal 9259 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 O($To1UZHv~{Qm*6e(k;h literal 0 HcmV?d00001 diff --git a/packages/ui/certd-client/src/views/framework/home/page-cover/image/logo.svg b/packages/ui/certd-client/src/views/framework/home/page-cover/image/logo.svg new file mode 100644 index 00000000..7a33425e --- /dev/null +++ b/packages/ui/certd-client/src/views/framework/home/page-cover/image/logo.svg @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/ui/certd-client/src/views/framework/home/page-cover/index.vue b/packages/ui/certd-client/src/views/framework/home/page-cover/index.vue new file mode 100644 index 00000000..976c620e --- /dev/null +++ b/packages/ui/certd-client/src/views/framework/home/page-cover/index.vue @@ -0,0 +1,139 @@ + + + diff --git a/packages/ui/certd-client/src/views/framework/login/index.vue b/packages/ui/certd-client/src/views/framework/login/index.vue new file mode 100644 index 00000000..a4b8728b --- /dev/null +++ b/packages/ui/certd-client/src/views/framework/login/index.vue @@ -0,0 +1,270 @@ + + + + diff --git a/packages/ui/certd-client/src/views/framework/register/index.vue b/packages/ui/certd-client/src/views/framework/register/index.vue new file mode 100644 index 00000000..d63e8e10 --- /dev/null +++ b/packages/ui/certd-client/src/views/framework/register/index.vue @@ -0,0 +1,178 @@ + + + + diff --git a/packages/ui/certd-client/src/views/sys/authority/permission/api.js b/packages/ui/certd-client/src/views/sys/authority/permission/api.js new file mode 100644 index 00000000..64627ea6 --- /dev/null +++ b/packages/ui/certd-client/src/views/sys/authority/permission/api.js @@ -0,0 +1,48 @@ +import { request } from "/src/api/service"; +const apiPrefix = "/sys/authority/permission"; +export async function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "post", + data: query + }); +} + +export async function GetTree() { + return request({ + url: apiPrefix + "/tree", + method: "post" + }); +} + +export async function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export async function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export async function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export async function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "post", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/sys/authority/permission/crud.jsx b/packages/ui/certd-client/src/views/sys/authority/permission/crud.jsx new file mode 100644 index 00000000..c8b91853 --- /dev/null +++ b/packages/ui/certd-client/src/views/sys/authority/permission/crud.jsx @@ -0,0 +1,150 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; + +export default function ({ expose }) { + const pageRequest = async (query) => { + const list = await api.GetTree(query); + + return { + current: 1, + records: list, + total: 10000, + pageSize: 10000 + }; + }; + + async function afterChange() { + await permissionTreeDict.reloadDict(); + } + const editRequest = async ({ form, row }) => { + form.id = row.id; + const ret = await api.UpdateObj(form); + await afterChange(); + return ret; + }; + const delRequest = async ({ row }) => { + const ret = await api.DelObj(row.id); + await afterChange(); + return ret; + }; + + const addRequest = async ({ form }) => { + const ret = await api.AddObj(form); + await afterChange(); + return ret; + }; + let permissionTreeDict = dict({ + url: "/sys/authority/permission/tree", + isTree: true, + value: "id", + label: "title", + async onReady({ dict }) { + dict.setData([{ id: -1, title: "根节点", children: dict.data }]); + } + }); + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + actionbar: { + show: false + }, + toolbar: { + show: false + }, + table: { + show: false + // scroll: { fixed: true } + }, + rowHandle: { + fixed: "right" + }, + search: { + show: false + }, + pagination: { + show: false, + pageSize: 100000 + }, + columns: { + id: { + title: "id", + type: "number", + form: { show: false }, // 表单配置 + column: { + width: 120, + sortable: "custom" + } + }, + title: { + title: "权限名称", + type: "text", + form: { + rules: [ + { required: true, message: "请输入权限名称" }, + { max: 50, message: "最大50个字符" } + ], + component: { + placeholder: "权限名称" + } + }, + column: { + width: 200 + } + }, + + permission: { + title: "权限代码", + type: "text", + column: { + width: 170 + }, + form: { + rules: [ + { required: true, message: "请输入权限代码" }, + { max: 100, message: "最大100个字符" } + ], + component: { + placeholder: "例如:sys:user:view" + } + } + }, + sort: { + title: "排序", + type: "number", + column: { + width: 100 + }, + form: { + value: 100, + rules: [{ required: true, type: "number", message: "排序号必填" }] + } + }, + parentId: { + title: "父节点", + type: "dict-tree", + column: { + width: 100 + }, + dict: permissionTreeDict, + form: { + value: -1, + component: { + multiple: false, + defaultExpandAll: true, + dict: { cache: false }, + fieldNames: { + value: "id", + label: "title" + } + } + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/sys/authority/permission/fs-permission-tree.vue b/packages/ui/certd-client/src/views/sys/authority/permission/fs-permission-tree.vue new file mode 100644 index 00000000..692ca1dd --- /dev/null +++ b/packages/ui/certd-client/src/views/sys/authority/permission/fs-permission-tree.vue @@ -0,0 +1,178 @@ + + + + + diff --git a/packages/ui/certd-client/src/views/sys/authority/permission/index.vue b/packages/ui/certd-client/src/views/sys/authority/permission/index.vue new file mode 100644 index 00000000..0005298e --- /dev/null +++ b/packages/ui/certd-client/src/views/sys/authority/permission/index.vue @@ -0,0 +1,90 @@ + + + + diff --git a/packages/ui/certd-client/src/views/sys/authority/role/api.js b/packages/ui/certd-client/src/views/sys/authority/role/api.js new file mode 100644 index 00000000..6793b6fa --- /dev/null +++ b/packages/ui/certd-client/src/views/sys/authority/role/api.js @@ -0,0 +1,70 @@ +import { request } from "/src/api/service"; +const apiPrefix = "/sys/authority/role"; +export async function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "post", + data: query + }); +} + +export async function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export async function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export async function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export async function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "post", + params: { id } + }); +} + +/** + * 获取角色权限资源 + * @param roleId + * @returns {*} + * @constructor + */ +export function getPermissionIds(roleId) { + return request({ + url: apiPrefix + "/getPermissionIds", + method: "post", + params: { id: roleId } + }); +} + +/** + * 授权 + * @param roleId + * @param permissionIds + * @returns {*} + * @constructor + */ +export function DoAuthz(roleId, permissionIds) { + return request({ + url: apiPrefix + "/authz", + method: "post", + data: { roleId, permissionIds } + }); +} diff --git a/packages/ui/certd-client/src/views/sys/authority/role/crud.jsx b/packages/ui/certd-client/src/views/sys/authority/role/crud.jsx new file mode 100644 index 00000000..a4c7290e --- /dev/null +++ b/packages/ui/certd-client/src/views/sys/authority/role/crud.jsx @@ -0,0 +1,81 @@ +import * as api from "./api"; +export default function ({ expose, authz }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + rowHandle: { + width: 300, + buttons: { + authz: { + type: "link", + text: "授权", + async click(context) { + await authz.authzOpen(context.record.id); + } + } + } + }, + columns: { + id: { + title: "id", + form: { show: false }, // 表单配置 + column: { + width: 70, + sorter: true + } + }, + name: { + title: "角色名称", + type: "text", + search: { show: true }, + form: { + rules: [ + { required: true, message: "请输入角色名称" }, + { max: 50, message: "最大50个字符" } + ] + }, // 表单配置 + column: { + sorter: true + } + }, + createTime: { + title: "创建时间", + type: "datetime", + column: { + sorter: true + }, + form: { + show: false + } + }, + updateTime: { + title: "更新时间", + type: "datetime", + column: { + sorter: true + }, + form: { show: false } // 表单配置 + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/sys/authority/role/index.vue b/packages/ui/certd-client/src/views/sys/authority/role/index.vue new file mode 100644 index 00000000..089cf1cd --- /dev/null +++ b/packages/ui/certd-client/src/views/sys/authority/role/index.vue @@ -0,0 +1,133 @@ + + + diff --git a/packages/ui/certd-client/src/views/sys/authority/user/api.js b/packages/ui/certd-client/src/views/sys/authority/user/api.js new file mode 100644 index 00000000..55474d50 --- /dev/null +++ b/packages/ui/certd-client/src/views/sys/authority/user/api.js @@ -0,0 +1,41 @@ +import { request } from "/src/api/service"; +const apiPrefix = "/sys/authority/user"; +export async function GetList(query) { + return request({ + url: apiPrefix + "/page", + method: "post", + data: query + }); +} + +export async function AddObj(obj) { + return request({ + url: apiPrefix + "/add", + method: "post", + data: obj + }); +} + +export async function UpdateObj(obj) { + return request({ + url: apiPrefix + "/update", + method: "post", + data: obj + }); +} + +export async function DelObj(id) { + return request({ + url: apiPrefix + "/delete", + method: "post", + params: { id } + }); +} + +export async function GetObj(id) { + return request({ + url: apiPrefix + "/info", + method: "post", + params: { id } + }); +} diff --git a/packages/ui/certd-client/src/views/sys/authority/user/crud.jsx b/packages/ui/certd-client/src/views/sys/authority/user/crud.jsx new file mode 100644 index 00000000..291e31f3 --- /dev/null +++ b/packages/ui/certd-client/src/views/sys/authority/user/crud.jsx @@ -0,0 +1,146 @@ +import * as api from "./api"; +import { dict } from "@fast-crud/fast-crud"; +export default function ({ expose }) { + const pageRequest = async (query) => { + return await api.GetList(query); + }; + const editRequest = async ({ form, row }) => { + form.id = row.id; + return await api.UpdateObj(form); + }; + const delRequest = async ({ row }) => { + return await api.DelObj(row.id); + }; + + const addRequest = async ({ form }) => { + return await api.AddObj(form); + }; + return { + crudOptions: { + request: { + pageRequest, + addRequest, + editRequest, + delRequest + }, + rowHandle: { + fixed: "right" + }, + table: { + scroll: { + //使用固定列时需要设置此值,并且大于等于列宽度之和的值 + x: 1400 + } + }, + columns: { + id: { + title: "id", + form: { show: false }, // 表单配置 + column: { + width: 70, + sorter: true + } + }, + createTime: { + title: "创建时间", + type: "datetime", + form: { show: false }, // 表单配置 + column: { + width: 180, + sorter: true + } + }, + // updateTime: { + // title: "修改时间", + // type: "datetime", + // form: { show: false }, // 表单配置 + // column: { + // sortable: "update_time", + // width: 180 + // } + // }, + username: { + title: "用户名", + type: "text", + search: { show: true }, // 开启查询 + form: { + rules: [ + { required: true, message: "请输入用户名" }, + { max: 50, message: "最大50个字符" } + ] + }, + editForm: { component: { disabled: true } }, + column: { + sorter: true + } + }, + password: { + title: "密码", + type: "text", + key: "password", + column: { + show: false + }, + form: { + rules: [{ max: 50, message: "最大50个字符" }], + component: { + showPassword: true + }, + helper: "填写则修改密码" + } + }, + nickName: { + title: "昵称", + type: "text", + search: { show: true }, // 开启查询 + form: { + rules: [{ max: 50, message: "最大50个字符" }] + }, + column: { + sorter: true + } + }, + avatar: { + title: "头像", + type: "cropper-uploader", + column: { + width: 100, + component: { + //设置高度,修复操作列错位的问题 + style: { + height: "30px", + width: "auto" + } + } + } + }, + remark: { + title: "备注", + type: "text", + column: { + sorter: true + }, + form: { + rules: [{ max: 100, message: "最大100个字符" }] + } + }, + roles: { + title: "角色", + type: "dict-select", + dict: dict({ + url: "/sys/authority/role/list", + value: "id", + label: "name" + }), // 数据字典 + form: { + component: { mode: "multiple" } + }, + column: { + width: 250, + sortable: true + } + } + } + } + }; +} diff --git a/packages/ui/certd-client/src/views/sys/authority/user/index.vue b/packages/ui/certd-client/src/views/sys/authority/user/index.vue new file mode 100644 index 00000000..33f0c7a5 --- /dev/null +++ b/packages/ui/certd-client/src/views/sys/authority/user/index.vue @@ -0,0 +1,45 @@ + + + diff --git a/packages/ui/certd-client/tailwind.config.js b/packages/ui/certd-client/tailwind.config.js new file mode 100644 index 00000000..ec39f7e5 --- /dev/null +++ b/packages/ui/certd-client/tailwind.config.js @@ -0,0 +1,11 @@ +module.exports = { + purge: [], + darkMode: false, // or 'media' or 'class' + theme: { + extend: {} + }, + variants: { + extend: {} + }, + plugins: [] +}; diff --git a/packages/ui/certd-client/tests/unit/example.spec.ts b/packages/ui/certd-client/tests/unit/example.spec.ts new file mode 100644 index 00000000..bc9939b6 --- /dev/null +++ b/packages/ui/certd-client/tests/unit/example.spec.ts @@ -0,0 +1,13 @@ +import { expect } from 'chai' +import { shallowMount } from '@vue/test-utils' +import HelloWorld from '@/components/HelloWorld.vue' + +describe('HelloWorld.vue', () => { + it('renders props.msg when passed', () => { + const msg = 'new message' + const wrapper = shallowMount(HelloWorld, { + props: { msg } + }) + expect(wrapper.text()).to.include(msg) + }) +}) diff --git a/packages/ui/certd-client/tsconfig.json b/packages/ui/certd-client/tsconfig.json new file mode 100644 index 00000000..3fb89b64 --- /dev/null +++ b/packages/ui/certd-client/tsconfig.json @@ -0,0 +1,46 @@ +{ + "compilerOptions": { + // 这样就可以对 `this` 上的数据属性进行更严格的推断` + "noImplicitAny": false, + "target": "esnext", + "module": "esnext", + "strict": true, + "jsx": "preserve", + "importHelpers": true, + "moduleResolution": "node", + "experimentalDecorators": true, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strictNullChecks" :false, + "sourceMap": true, + "baseUrl": ".", + "outDir": "./dist/ts", + "types": [ + "mocha", + "chai", + "node" + ], + "paths": { + "/@/*": ["src/*"], + "/src/*": ["src/*"], + "/#/*": ["types/*"] + }, + "lib": [ + "esnext", + "dom", + "dom.iterable", + "scripthost" + ] + }, + "include": [ + "src/**/*.ts", + "src/**/*.tsx", + "src/**/*.vue", + "tests/**/*.ts", + "tests/**/*.tsx" + ], + "exclude": [ + "node_modules" + ] +} diff --git a/packages/ui/certd-client/vite.config.ts b/packages/ui/certd-client/vite.config.ts new file mode 100644 index 00000000..15ea9604 --- /dev/null +++ b/packages/ui/certd-client/vite.config.ts @@ -0,0 +1,101 @@ +import vue from "@vitejs/plugin-vue"; +import vueJsx from "@vitejs/plugin-vue-jsx"; +import visualizer from "rollup-plugin-visualizer"; +import viteCompression from "vite-plugin-compression"; +import PurgeIcons from "vite-plugin-purge-icons"; +import * as path from "path"; +import WindiCSS from "vite-plugin-windicss"; +// import { generateModifyVars } from "./build/modify-vars"; +// import { configThemePlugin } from "./build/theme-plugin"; +// import OptimizationPersist from "vite-plugin-optimize-persist"; +// import PkgConfig from "vite-plugin-package-config"; +// https://vitejs.dev/config/ +// 增加环境变量 _ +process.env.VITE_APP_VERSION = require("./package.json").version; +process.env.VITE_APP_BUILD_TIME = require("dayjs")().format("YYYY-M-D HH:mm:ss"); + +export default ({ command, mode }) => { + console.log("args", command, mode); + + let devServerFs: any = {}; + let devAlias: any[] = []; + if (mode.startsWith("debug")) { + devAlias = [ + { find: /@fast-crud\/fast-crud\/dist/, replacement: path.resolve("../../fast-crud/src/") }, + { find: /@fast-crud\/fast-crud$/, replacement: path.resolve("../../fast-crud/src/") }, + { find: /@fast-crud\/fast-extends\/dist/, replacement: path.resolve("../../fast-extends/src/") }, + { find: /@fast-crud\/fast-extends$/, replacement: path.resolve("../../fast-extends/src/") }, + { find: /@fast-crud\/ui-antdv$/, replacement: path.resolve("../../ui/ui-antdv/src/") } + ]; + devServerFs = { + // 如果是你自己的项目,这项可以删掉 + // 这里配置dev启动时读取的项目根目录 + allow: ["../../"] + }; + console.log("devAlias", devAlias); + } + + return { + base: "/antdv/", + plugins: [ + vueJsx(), + vue(), + // 压缩build后的代码 + viteCompression(), + PurgeIcons({ + // iconSource: "local" + // remoteDataAPI: "https://gitee.com/fast-crud/collections-json/raw/master/json", + // includedCollections: ["ion"] + }), + //主题色替换 + //...configThemePlugin(true), + // viteThemePlugin({ + // // Match the color to be modified + // colorVariables: ["#1890ff", "#40a9ff"] + // }), + // windicss tailwindcss + WindiCSS() + ], + esbuild: { + // pure: ["console.log", "debugger"], + jsxFactory: "h", + jsxFragment: "Fragment" + }, + resolve: { + alias: [ + ...devAlias, + { find: "/@", replacement: path.resolve("./src") }, + { find: "/#", replacement: path.resolve("./types") } + ], + dedupe: ["vue"] + }, + optimizeDeps: { + include: ["ant-design-vue"] + }, + build: { + rollupOptions: { + plugins: [visualizer()] + } + }, + css: { + preprocessorOptions: { + less: { + // 修改默认主题颜色,配置less变量 + // modifyVars: generateModifyVars(), + javascriptEnabled: true + } + } + }, + server: { + port: 3002, + fs: devServerFs, + proxy: { + // with options + "/api": { + //配套后端 https://github.com/fast-crud/fs-server-js + target: "http://127.0.0.1:7001" + } + } + } + }; +}; diff --git a/packages/ui/certd-client/windi.config.js b/packages/ui/certd-client/windi.config.js new file mode 100644 index 00000000..6d82c495 --- /dev/null +++ b/packages/ui/certd-client/windi.config.js @@ -0,0 +1,6 @@ +// windi.config.ts +export default { + attributify: { + prefix: "w:" + } +};