commit aa8c4990c0679abe4b6647d21e7ae92674324c92 Author: fuxiaochun Date: Tue Aug 8 12:53:15 2023 +0800 init project diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..3ec1029 --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# production +/build +/dist + +# misc +.DS_Store +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +npm-debug.log* +yarn-debug.log* +yarn-error.log* +package-lock.json \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..bc89a7c --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +# aigc + +This template should help get you started developing with Vue 3 in Vite. + +## Recommended IDE Setup + +[VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin). + +## Customize configuration + +See [Vite Configuration Reference](https://vitejs.dev/config/). + +## Project Setup + +```sh +npm install +``` + +### Compile and Hot-Reload for Development + +```sh +npm run dev +``` + +### Compile and Minify for Production + +```sh +npm run build +``` + +### Lint with [ESLint](https://eslint.org/) + +```sh +npm run lint +``` diff --git a/index.html b/index.html new file mode 100644 index 0000000..26b31ad --- /dev/null +++ b/index.html @@ -0,0 +1,14 @@ + + + + + + + + aigc + + +
+ + + diff --git a/package.json b/package.json new file mode 100644 index 0000000..f7bb137 --- /dev/null +++ b/package.json @@ -0,0 +1,43 @@ +{ + "name": "aigc", + "version": "0.0.0", + "private": true, + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview", + "lint": "eslint . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore", + "format": "prettier --write src/" + }, + "dependencies": { + "@traptitech/markdown-it-katex": "^3.6.0", + "axios": "^1.4.0", + "echarts": "^5.4.3", + "highlight.js": "^11.8.0", + "lodash-es": "^4.17.21", + "markdown-it": "^13.0.1", + "markdown-it-link-attributes": "^4.0.1", + "pinia": "^2.1.3", + "resize-observer-polyfill": "^1.5.1", + "swiper": "^10.1.0", + "vant": "^4.6.4", + "vue": "^3.3.4", + "vue-router": "^4.2.2" + }, + "devDependencies": { + "@rushstack/eslint-patch": "^1.2.0", + "@vitejs/plugin-vue": "^4.2.3", + "@vitejs/plugin-vue-jsx": "^3.0.1", + "@vue/eslint-config-prettier": "^7.1.0", + "eslint": "^8.39.0", + "eslint-plugin-vue": "^9.11.0", + "prettier": "^2.8.8", + "sass": "^1.63.6", + "sass-loader": "^13.3.2", + "unplugin-vue-components": "^0.25.1", + "vite": "^4.3.9", + "vite-plugin-svg-icons": "^2.0.1", + "vite-plugin-windicss": "^1.9.0", + "windicss": "^3.5.6" + } +} diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..df36fcf Binary files /dev/null and b/public/favicon.ico differ diff --git a/src/App.vue b/src/App.vue new file mode 100644 index 0000000..9e54bca --- /dev/null +++ b/src/App.vue @@ -0,0 +1,25 @@ + + + + + diff --git a/src/assets/css/base.css b/src/assets/css/base.css new file mode 100644 index 0000000..72abe2b --- /dev/null +++ b/src/assets/css/base.css @@ -0,0 +1,90 @@ +/* color palette from */ +:root { + --vt-c-white: #ffffff; + --vt-c-white-soft: #f8f8f8; + --vt-c-white-mute: #f2f2f2; + + --vt-c-black: #181818; + --vt-c-black-soft: #222222; + --vt-c-black-mute: #282828; + + --vt-c-indigo: #2c3e50; + + --vt-c-divider-light-1: rgba(60, 60, 60, 0.29); + --vt-c-divider-light-2: rgba(60, 60, 60, 0.12); + --vt-c-divider-dark-1: rgba(84, 84, 84, 0.65); + --vt-c-divider-dark-2: rgba(84, 84, 84, 0.48); + + --vt-c-text-light-1: var(--vt-c-white); + --vt-c-text-light-2: rgba(60, 60, 60, 0.66); + --vt-c-text-dark-1: var(--vt-c-white); + --vt-c-text-dark-2: rgba(235, 235, 235, 0.64); +} + +/* semantic color variables for this project */ +:root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-light-2); + --color-border-hover: var(--vt-c-divider-light-1); + + --color-heading: var(--vt-c-text-light-1); + --color-text: var(--vt-c-text-light-1); + + --section-gap: 160px; +} + +@media (prefers-color-scheme: dark) { + :root { + --color-background: var(--vt-c-black); + --color-background-soft: var(--vt-c-black-soft); + --color-background-mute: var(--vt-c-black-mute); + + --color-border: var(--vt-c-divider-dark-2); + --color-border-hover: var(--vt-c-divider-dark-1); + + --color-heading: var(--vt-c-text-dark-1); + --color-text: var(--vt-c-text-dark-2); + } +} + +*, +*::before, +*::after { + box-sizing: border-box; + margin: 0; + font-weight: normal; +} + +body { + height: 100vh; + /* min-height: 100vh; */ + color: var(--color-text); + background: var(--color-background); + transition: color 0.5s, background-color 0.5s; + line-height: 1.6; + font-family: Inter, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, + Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', + sans-serif; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* fade-slide */ +.fade-slide-leave-active, +.fade-slide-enter-active { + transition: all 0.3s; +} + +.fade-slide-enter-from { + transform: translateX(-30px); + opacity: 0; +} + +.fade-slide-leave-to { + transform: translateX(30px); + opacity: 0; +} diff --git a/src/assets/css/github-markdown.scss b/src/assets/css/github-markdown.scss new file mode 100644 index 0000000..c928577 --- /dev/null +++ b/src/assets/css/github-markdown.scss @@ -0,0 +1,1102 @@ +html.dark { + .markdown-body { + color-scheme: dark; + --color-prettylights-syntax-comment: #8b949e; + --color-prettylights-syntax-constant: #79c0ff; + --color-prettylights-syntax-entity: #d2a8ff; + --color-prettylights-syntax-storage-modifier-import: #c9d1d9; + --color-prettylights-syntax-entity-tag: #7ee787; + --color-prettylights-syntax-keyword: #ff7b72; + --color-prettylights-syntax-string: #a5d6ff; + --color-prettylights-syntax-variable: #ffa657; + --color-prettylights-syntax-brackethighlighter-unmatched: #f85149; + --color-prettylights-syntax-invalid-illegal-text: #f0f6fc; + --color-prettylights-syntax-invalid-illegal-bg: #8e1519; + --color-prettylights-syntax-carriage-return-text: #f0f6fc; + --color-prettylights-syntax-carriage-return-bg: #b62324; + --color-prettylights-syntax-string-regexp: #7ee787; + --color-prettylights-syntax-markup-list: #f2cc60; + --color-prettylights-syntax-markup-heading: #1f6feb; + --color-prettylights-syntax-markup-italic: #c9d1d9; + --color-prettylights-syntax-markup-bold: #c9d1d9; + --color-prettylights-syntax-markup-deleted-text: #ffdcd7; + --color-prettylights-syntax-markup-deleted-bg: #67060c; + --color-prettylights-syntax-markup-inserted-text: #aff5b4; + --color-prettylights-syntax-markup-inserted-bg: #033a16; + --color-prettylights-syntax-markup-changed-text: #ffdfb6; + --color-prettylights-syntax-markup-changed-bg: #5a1e02; + --color-prettylights-syntax-markup-ignored-text: #c9d1d9; + --color-prettylights-syntax-markup-ignored-bg: #1158c7; + --color-prettylights-syntax-meta-diff-range: #d2a8ff; + --color-prettylights-syntax-brackethighlighter-angle: #8b949e; + --color-prettylights-syntax-sublimelinter-gutter-mark: #484f58; + --color-prettylights-syntax-constant-other-reference-link: #a5d6ff; + --color-fg-default: #c9d1d9; + --color-fg-muted: #8b949e; + --color-fg-subtle: #6e7681; + --color-canvas-default: #0d1117; + --color-canvas-subtle: #161b22; + --color-border-default: #30363d; + --color-border-muted: #21262d; + --color-neutral-muted: rgba(110,118,129,0.4); + --color-accent-fg: #58a6ff; + --color-accent-emphasis: #1f6feb; + --color-attention-subtle: rgba(187,128,9,0.15); + --color-danger-fg: #f85149; + } +} + +html { + .markdown-body { + color-scheme: light; + --color-prettylights-syntax-comment: #6e7781; + --color-prettylights-syntax-constant: #0550ae; + --color-prettylights-syntax-entity: #8250df; + --color-prettylights-syntax-storage-modifier-import: #24292f; + --color-prettylights-syntax-entity-tag: #116329; + --color-prettylights-syntax-keyword: #cf222e; + --color-prettylights-syntax-string: #0a3069; + --color-prettylights-syntax-variable: #953800; + --color-prettylights-syntax-brackethighlighter-unmatched: #82071e; + --color-prettylights-syntax-invalid-illegal-text: #f6f8fa; + --color-prettylights-syntax-invalid-illegal-bg: #82071e; + --color-prettylights-syntax-carriage-return-text: #f6f8fa; + --color-prettylights-syntax-carriage-return-bg: #cf222e; + --color-prettylights-syntax-string-regexp: #116329; + --color-prettylights-syntax-markup-list: #3b2300; + --color-prettylights-syntax-markup-heading: #0550ae; + --color-prettylights-syntax-markup-italic: #24292f; + --color-prettylights-syntax-markup-bold: #24292f; + --color-prettylights-syntax-markup-deleted-text: #82071e; + --color-prettylights-syntax-markup-deleted-bg: #ffebe9; + --color-prettylights-syntax-markup-inserted-text: #116329; + --color-prettylights-syntax-markup-inserted-bg: #dafbe1; + --color-prettylights-syntax-markup-changed-text: #953800; + --color-prettylights-syntax-markup-changed-bg: #ffd8b5; + --color-prettylights-syntax-markup-ignored-text: #eaeef2; + --color-prettylights-syntax-markup-ignored-bg: #0550ae; + --color-prettylights-syntax-meta-diff-range: #8250df; + --color-prettylights-syntax-brackethighlighter-angle: #57606a; + --color-prettylights-syntax-sublimelinter-gutter-mark: #8c959f; + --color-prettylights-syntax-constant-other-reference-link: #0a3069; + --color-fg-default: #24292f; + --color-fg-muted: #57606a; + --color-fg-subtle: #6e7781; + --color-canvas-default: #ffffff; + --color-canvas-subtle: #f6f8fa; + --color-border-default: #d0d7de; + --color-border-muted: hsla(210,18%,87%,1); + --color-neutral-muted: rgba(175,184,193,0.2); + --color-accent-fg: #0969da; + --color-accent-emphasis: #0969da; + --color-attention-subtle: #fff8c5; + --color-danger-fg: #cf222e; + } +} + +.markdown-body { + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; + margin: 0; + color: var(--color-fg-default); + background-color: var(--color-canvas-default); + font-family: -apple-system,BlinkMacSystemFont,"Segoe UI","Noto Sans",Helvetica,Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji"; + font-size: 16px; + line-height: 1.5; + word-wrap: break-word; +} + +.markdown-body .octicon { + display: inline-block; + fill: currentColor; + vertical-align: text-bottom; +} + +.markdown-body h1:hover .anchor .octicon-link:before, +.markdown-body h2:hover .anchor .octicon-link:before, +.markdown-body h3:hover .anchor .octicon-link:before, +.markdown-body h4:hover .anchor .octicon-link:before, +.markdown-body h5:hover .anchor .octicon-link:before, +.markdown-body h6:hover .anchor .octicon-link:before { + width: 16px; + height: 16px; + content: ' '; + display: inline-block; + background-color: currentColor; + -webkit-mask-image: url("data:image/svg+xml,"); + mask-image: url("data:image/svg+xml,"); +} + +.markdown-body details, +.markdown-body figcaption, +.markdown-body figure { + display: block; +} + +.markdown-body summary { + display: list-item; +} + +.markdown-body [hidden] { + display: none !important; +} + +.markdown-body a { + background-color: transparent; + color: var(--color-accent-fg); + text-decoration: none; +} + +.markdown-body abbr[title] { + border-bottom: none; + text-decoration: underline dotted; +} + +.markdown-body b, +.markdown-body strong { + font-weight: var(--base-text-weight-semibold, 600); +} + +.markdown-body dfn { + font-style: italic; +} + +.markdown-body h1 { + margin: .67em 0; + font-weight: var(--base-text-weight-semibold, 600); + padding-bottom: .3em; + font-size: 2em; + border-bottom: 1px solid var(--color-border-muted); +} + +.markdown-body mark { + background-color: var(--color-attention-subtle); + color: var(--color-fg-default); +} + +.markdown-body small { + font-size: 90%; +} + +.markdown-body sub, +.markdown-body sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +.markdown-body sub { + bottom: -0.25em; +} + +.markdown-body sup { + top: -0.5em; +} + +.markdown-body img { + border-style: none; + max-width: 100%; + box-sizing: content-box; + background-color: var(--color-canvas-default); +} + +.markdown-body code, +.markdown-body kbd, +.markdown-body pre, +.markdown-body samp { + font-family: monospace; + font-size: 1em; +} + +.markdown-body figure { + margin: 1em 40px; +} + +.markdown-body hr { + box-sizing: content-box; + overflow: hidden; + background: transparent; + border-bottom: 1px solid var(--color-border-muted); + height: .25em; + padding: 0; + margin: 24px 0; + background-color: var(--color-border-default); + border: 0; +} + +.markdown-body input { + font: inherit; + margin: 0; + overflow: visible; + font-family: inherit; + font-size: inherit; + line-height: inherit; +} + +.markdown-body [type=button], +.markdown-body [type=reset], +.markdown-body [type=submit] { + -webkit-appearance: button; +} + +.markdown-body [type=checkbox], +.markdown-body [type=radio] { + box-sizing: border-box; + padding: 0; +} + +.markdown-body [type=number]::-webkit-inner-spin-button, +.markdown-body [type=number]::-webkit-outer-spin-button { + height: auto; +} + +.markdown-body [type=search]::-webkit-search-cancel-button, +.markdown-body [type=search]::-webkit-search-decoration { + -webkit-appearance: none; +} + +.markdown-body ::-webkit-input-placeholder { + color: inherit; + opacity: .54; +} + +.markdown-body ::-webkit-file-upload-button { + -webkit-appearance: button; + font: inherit; +} + +.markdown-body a:hover { + text-decoration: underline; +} + +.markdown-body ::placeholder { + color: var(--color-fg-subtle); + opacity: 1; +} + +.markdown-body hr::before { + display: table; + content: ""; +} + +.markdown-body hr::after { + display: table; + clear: both; + content: ""; +} + +.markdown-body table { + border-spacing: 0; + border-collapse: collapse; + display: block; + width: max-content; + max-width: 100%; + overflow: auto; +} + +.markdown-body td, +.markdown-body th { + padding: 0; +} + +.markdown-body details summary { + cursor: pointer; +} + +.markdown-body details:not([open])>*:not(summary) { + display: none !important; +} + +.markdown-body a:focus, +.markdown-body [role=button]:focus, +.markdown-body input[type=radio]:focus, +.markdown-body input[type=checkbox]:focus { + outline: 2px solid var(--color-accent-fg); + outline-offset: -2px; + box-shadow: none; +} + +.markdown-body a:focus:not(:focus-visible), +.markdown-body [role=button]:focus:not(:focus-visible), +.markdown-body input[type=radio]:focus:not(:focus-visible), +.markdown-body input[type=checkbox]:focus:not(:focus-visible) { + outline: solid 1px transparent; +} + +.markdown-body a:focus-visible, +.markdown-body [role=button]:focus-visible, +.markdown-body input[type=radio]:focus-visible, +.markdown-body input[type=checkbox]:focus-visible { + outline: 2px solid var(--color-accent-fg); + outline-offset: -2px; + box-shadow: none; +} + +.markdown-body a:not([class]):focus, +.markdown-body a:not([class]):focus-visible, +.markdown-body input[type=radio]:focus, +.markdown-body input[type=radio]:focus-visible, +.markdown-body input[type=checkbox]:focus, +.markdown-body input[type=checkbox]:focus-visible { + outline-offset: 0; +} + +.markdown-body kbd { + display: inline-block; + padding: 3px 5px; + font: 11px ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; + line-height: 10px; + color: var(--color-fg-default); + vertical-align: middle; + background-color: var(--color-canvas-subtle); + border: solid 1px var(--color-neutral-muted); + border-bottom-color: var(--color-neutral-muted); + border-radius: 6px; + box-shadow: inset 0 -1px 0 var(--color-neutral-muted); +} + +.markdown-body h1, +.markdown-body h2, +.markdown-body h3, +.markdown-body h4, +.markdown-body h5, +.markdown-body h6 { + margin-top: 24px; + margin-bottom: 16px; + font-weight: var(--base-text-weight-semibold, 600); + line-height: 1.25; +} + +.markdown-body h2 { + font-weight: var(--base-text-weight-semibold, 600); + padding-bottom: .3em; + font-size: 1.5em; + border-bottom: 1px solid var(--color-border-muted); +} + +.markdown-body h3 { + font-weight: var(--base-text-weight-semibold, 600); + font-size: 1.25em; +} + +.markdown-body h4 { + font-weight: var(--base-text-weight-semibold, 600); + font-size: 1em; +} + +.markdown-body h5 { + font-weight: var(--base-text-weight-semibold, 600); + font-size: .875em; +} + +.markdown-body h6 { + font-weight: var(--base-text-weight-semibold, 600); + font-size: .85em; + color: var(--color-fg-muted); +} + +.markdown-body p { + margin-top: 0; + margin-bottom: 10px; +} + +.markdown-body blockquote { + margin: 0; + padding: 0 1em; + color: var(--color-fg-muted); + border-left: .25em solid var(--color-border-default); +} + +.markdown-body ul, +.markdown-body ol { + margin-top: 0; + margin-bottom: 0; + padding-left: 2em; +} + +.markdown-body ol ol, +.markdown-body ul ol { + list-style-type: lower-roman; +} + +.markdown-body ul ul ol, +.markdown-body ul ol ol, +.markdown-body ol ul ol, +.markdown-body ol ol ol { + list-style-type: lower-alpha; +} + +.markdown-body dd { + margin-left: 0; +} + +.markdown-body tt, +.markdown-body code, +.markdown-body samp { + font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; + font-size: 12px; +} + +.markdown-body pre { + margin-top: 0; + margin-bottom: 0; + font-family: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; + font-size: 12px; + word-wrap: normal; +} + +.markdown-body .octicon { + display: inline-block; + overflow: visible !important; + vertical-align: text-bottom; + fill: currentColor; +} + +.markdown-body input::-webkit-outer-spin-button, +.markdown-body input::-webkit-inner-spin-button { + margin: 0; + -webkit-appearance: none; + appearance: none; +} + +.markdown-body::before { + display: table; + content: ""; +} + +.markdown-body::after { + display: table; + clear: both; + content: ""; +} + +.markdown-body>*:first-child { + margin-top: 0 !important; +} + +.markdown-body>*:last-child { + margin-bottom: 0 !important; +} + +.markdown-body a:not([href]) { + color: inherit; + text-decoration: none; +} + +.markdown-body .absent { + color: var(--color-danger-fg); +} + +.markdown-body .anchor { + float: left; + padding-right: 4px; + margin-left: -20px; + line-height: 1; +} + +.markdown-body .anchor:focus { + outline: none; +} + +.markdown-body p, +.markdown-body blockquote, +.markdown-body ul, +.markdown-body ol, +.markdown-body dl, +.markdown-body table, +.markdown-body pre, +.markdown-body details { + margin-top: 0; + margin-bottom: 16px; +} + +.markdown-body blockquote>:first-child { + margin-top: 0; +} + +.markdown-body blockquote>:last-child { + margin-bottom: 0; +} + +.markdown-body h1 .octicon-link, +.markdown-body h2 .octicon-link, +.markdown-body h3 .octicon-link, +.markdown-body h4 .octicon-link, +.markdown-body h5 .octicon-link, +.markdown-body h6 .octicon-link { + color: var(--color-fg-default); + vertical-align: middle; + visibility: hidden; +} + +.markdown-body h1:hover .anchor, +.markdown-body h2:hover .anchor, +.markdown-body h3:hover .anchor, +.markdown-body h4:hover .anchor, +.markdown-body h5:hover .anchor, +.markdown-body h6:hover .anchor { + text-decoration: none; +} + +.markdown-body h1:hover .anchor .octicon-link, +.markdown-body h2:hover .anchor .octicon-link, +.markdown-body h3:hover .anchor .octicon-link, +.markdown-body h4:hover .anchor .octicon-link, +.markdown-body h5:hover .anchor .octicon-link, +.markdown-body h6:hover .anchor .octicon-link { + visibility: visible; +} + +.markdown-body h1 tt, +.markdown-body h1 code, +.markdown-body h2 tt, +.markdown-body h2 code, +.markdown-body h3 tt, +.markdown-body h3 code, +.markdown-body h4 tt, +.markdown-body h4 code, +.markdown-body h5 tt, +.markdown-body h5 code, +.markdown-body h6 tt, +.markdown-body h6 code { + padding: 0 .2em; + font-size: inherit; +} + +.markdown-body summary h1, +.markdown-body summary h2, +.markdown-body summary h3, +.markdown-body summary h4, +.markdown-body summary h5, +.markdown-body summary h6 { + display: inline-block; +} + +.markdown-body summary h1 .anchor, +.markdown-body summary h2 .anchor, +.markdown-body summary h3 .anchor, +.markdown-body summary h4 .anchor, +.markdown-body summary h5 .anchor, +.markdown-body summary h6 .anchor { + margin-left: -40px; +} + +.markdown-body summary h1, +.markdown-body summary h2 { + padding-bottom: 0; + border-bottom: 0; +} + +.markdown-body ul.no-list, +.markdown-body ol.no-list { + padding: 0; + list-style-type: none; +} + +.markdown-body ol[type=a] { + list-style-type: lower-alpha; +} + +.markdown-body ol[type=A] { + list-style-type: upper-alpha; +} + +.markdown-body ol[type=i] { + list-style-type: lower-roman; +} + +.markdown-body ol[type=I] { + list-style-type: upper-roman; +} + +.markdown-body ol[type="1"] { + list-style-type: decimal; +} + +.markdown-body div>ol:not([type]) { + list-style-type: decimal; +} + +.markdown-body ul ul, +.markdown-body ul ol, +.markdown-body ol ol, +.markdown-body ol ul { + margin-top: 0; + margin-bottom: 0; +} + +.markdown-body li>p { + margin-top: 16px; +} + +.markdown-body li+li { + margin-top: .25em; +} + +.markdown-body dl { + padding: 0; +} + +.markdown-body dl dt { + padding: 0; + margin-top: 16px; + font-size: 1em; + font-style: italic; + font-weight: var(--base-text-weight-semibold, 600); +} + +.markdown-body dl dd { + padding: 0 16px; + margin-bottom: 16px; +} + +.markdown-body table th { + font-weight: var(--base-text-weight-semibold, 600); +} + +.markdown-body table th, +.markdown-body table td { + padding: 6px 13px; + border: 1px solid var(--color-border-default); +} + +.markdown-body table tr { + background-color: var(--color-canvas-default); + border-top: 1px solid var(--color-border-muted); +} + +.markdown-body table tr:nth-child(2n) { + background-color: var(--color-canvas-subtle); +} + +.markdown-body table img { + background-color: transparent; +} + +.markdown-body img[align=right] { + padding-left: 20px; +} + +.markdown-body img[align=left] { + padding-right: 20px; +} + +.markdown-body .emoji { + max-width: none; + vertical-align: text-top; + background-color: transparent; +} + +.markdown-body span.frame { + display: block; + overflow: hidden; +} + +.markdown-body span.frame>span { + display: block; + float: left; + width: auto; + padding: 7px; + margin: 13px 0 0; + overflow: hidden; + border: 1px solid var(--color-border-default); +} + +.markdown-body span.frame span img { + display: block; + float: left; +} + +.markdown-body span.frame span span { + display: block; + padding: 5px 0 0; + clear: both; + color: var(--color-fg-default); +} + +.markdown-body span.align-center { + display: block; + overflow: hidden; + clear: both; +} + +.markdown-body span.align-center>span { + display: block; + margin: 13px auto 0; + overflow: hidden; + text-align: center; +} + +.markdown-body span.align-center span img { + margin: 0 auto; + text-align: center; +} + +.markdown-body span.align-right { + display: block; + overflow: hidden; + clear: both; +} + +.markdown-body span.align-right>span { + display: block; + margin: 13px 0 0; + overflow: hidden; + text-align: right; +} + +.markdown-body span.align-right span img { + margin: 0; + text-align: right; +} + +.markdown-body span.float-left { + display: block; + float: left; + margin-right: 13px; + overflow: hidden; +} + +.markdown-body span.float-left span { + margin: 13px 0 0; +} + +.markdown-body span.float-right { + display: block; + float: right; + margin-left: 13px; + overflow: hidden; +} + +.markdown-body span.float-right>span { + display: block; + margin: 13px auto 0; + overflow: hidden; + text-align: right; +} + +.markdown-body code, +.markdown-body tt { + padding: .2em .4em; + margin: 0; + font-size: 85%; + white-space: break-spaces; + background-color: var(--color-neutral-muted); + border-radius: 6px; +} + +.markdown-body code br, +.markdown-body tt br { + display: none; +} + +.markdown-body del code { + text-decoration: inherit; +} + +.markdown-body samp { + font-size: 85%; +} + +.markdown-body pre code { + font-size: 100%; +} + +.markdown-body pre>code { + padding: 0; + margin: 0; + word-break: normal; + white-space: pre; + background: transparent; + border: 0; +} + +.markdown-body .highlight { + margin-bottom: 16px; +} + +.markdown-body .highlight pre { + margin-bottom: 0; + word-break: normal; +} + +.markdown-body .highlight pre, +.markdown-body pre { + padding: 16px; + overflow: auto; + font-size: 85%; + line-height: 1.45; + background-color: var(--color-canvas-subtle); + border-radius: 6px; +} + +.markdown-body pre code, +.markdown-body pre tt { + display: inline; + max-width: auto; + padding: 0; + margin: 0; + overflow: visible; + line-height: inherit; + word-wrap: normal; + background-color: transparent; + border: 0; +} + +.markdown-body .csv-data td, +.markdown-body .csv-data th { + padding: 5px; + overflow: hidden; + font-size: 12px; + line-height: 1; + text-align: left; + white-space: nowrap; +} + +.markdown-body .csv-data .blob-num { + padding: 10px 8px 9px; + text-align: right; + background: var(--color-canvas-default); + border: 0; +} + +.markdown-body .csv-data tr { + border-top: 0; +} + +.markdown-body .csv-data th { + font-weight: var(--base-text-weight-semibold, 600); + background: var(--color-canvas-subtle); + border-top: 0; +} + +.markdown-body [data-footnote-ref]::before { + content: "["; +} + +.markdown-body [data-footnote-ref]::after { + content: "]"; +} + +.markdown-body .footnotes { + font-size: 12px; + color: var(--color-fg-muted); + border-top: 1px solid var(--color-border-default); +} + +.markdown-body .footnotes ol { + padding-left: 16px; +} + +.markdown-body .footnotes ol ul { + display: inline-block; + padding-left: 16px; + margin-top: 16px; +} + +.markdown-body .footnotes li { + position: relative; +} + +.markdown-body .footnotes li:target::before { + position: absolute; + top: -8px; + right: -8px; + bottom: -8px; + left: -24px; + pointer-events: none; + content: ""; + border: 2px solid var(--color-accent-emphasis); + border-radius: 6px; +} + +.markdown-body .footnotes li:target { + color: var(--color-fg-default); +} + +.markdown-body .footnotes .data-footnote-backref g-emoji { + font-family: monospace; +} + +.markdown-body .pl-c { + color: var(--color-prettylights-syntax-comment); +} + +.markdown-body .pl-c1, +.markdown-body .pl-s .pl-v { + color: var(--color-prettylights-syntax-constant); +} + +.markdown-body .pl-e, +.markdown-body .pl-en { + color: var(--color-prettylights-syntax-entity); +} + +.markdown-body .pl-smi, +.markdown-body .pl-s .pl-s1 { + color: var(--color-prettylights-syntax-storage-modifier-import); +} + +.markdown-body .pl-ent { + color: var(--color-prettylights-syntax-entity-tag); +} + +.markdown-body .pl-k { + color: var(--color-prettylights-syntax-keyword); +} + +.markdown-body .pl-s, +.markdown-body .pl-pds, +.markdown-body .pl-s .pl-pse .pl-s1, +.markdown-body .pl-sr, +.markdown-body .pl-sr .pl-cce, +.markdown-body .pl-sr .pl-sre, +.markdown-body .pl-sr .pl-sra { + color: var(--color-prettylights-syntax-string); +} + +.markdown-body .pl-v, +.markdown-body .pl-smw { + color: var(--color-prettylights-syntax-variable); +} + +.markdown-body .pl-bu { + color: var(--color-prettylights-syntax-brackethighlighter-unmatched); +} + +.markdown-body .pl-ii { + color: var(--color-prettylights-syntax-invalid-illegal-text); + background-color: var(--color-prettylights-syntax-invalid-illegal-bg); +} + +.markdown-body .pl-c2 { + color: var(--color-prettylights-syntax-carriage-return-text); + background-color: var(--color-prettylights-syntax-carriage-return-bg); +} + +.markdown-body .pl-sr .pl-cce { + font-weight: bold; + color: var(--color-prettylights-syntax-string-regexp); +} + +.markdown-body .pl-ml { + color: var(--color-prettylights-syntax-markup-list); +} + +.markdown-body .pl-mh, +.markdown-body .pl-mh .pl-en, +.markdown-body .pl-ms { + font-weight: bold; + color: var(--color-prettylights-syntax-markup-heading); +} + +.markdown-body .pl-mi { + font-style: italic; + color: var(--color-prettylights-syntax-markup-italic); +} + +.markdown-body .pl-mb { + font-weight: bold; + color: var(--color-prettylights-syntax-markup-bold); +} + +.markdown-body .pl-md { + color: var(--color-prettylights-syntax-markup-deleted-text); + background-color: var(--color-prettylights-syntax-markup-deleted-bg); +} + +.markdown-body .pl-mi1 { + color: var(--color-prettylights-syntax-markup-inserted-text); + background-color: var(--color-prettylights-syntax-markup-inserted-bg); +} + +.markdown-body .pl-mc { + color: var(--color-prettylights-syntax-markup-changed-text); + background-color: var(--color-prettylights-syntax-markup-changed-bg); +} + +.markdown-body .pl-mi2 { + color: var(--color-prettylights-syntax-markup-ignored-text); + background-color: var(--color-prettylights-syntax-markup-ignored-bg); +} + +.markdown-body .pl-mdr { + font-weight: bold; + color: var(--color-prettylights-syntax-meta-diff-range); +} + +.markdown-body .pl-ba { + color: var(--color-prettylights-syntax-brackethighlighter-angle); +} + +.markdown-body .pl-sg { + color: var(--color-prettylights-syntax-sublimelinter-gutter-mark); +} + +.markdown-body .pl-corl { + text-decoration: underline; + color: var(--color-prettylights-syntax-constant-other-reference-link); +} + +.markdown-body g-emoji { + display: inline-block; + min-width: 1ch; + font-family: "Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol"; + font-size: 1em; + font-style: normal !important; + font-weight: var(--base-text-weight-normal, 400); + line-height: 1; + vertical-align: -0.075em; +} + +.markdown-body g-emoji img { + width: 1em; + height: 1em; +} + +.markdown-body .task-list-item { + list-style-type: none; +} + +.markdown-body .task-list-item label { + font-weight: var(--base-text-weight-normal, 400); +} + +.markdown-body .task-list-item.enabled label { + cursor: pointer; +} + +.markdown-body .task-list-item+.task-list-item { + margin-top: 4px; +} + +.markdown-body .task-list-item .handle { + display: none; +} + +.markdown-body .task-list-item-checkbox { + margin: 0 .2em .25em -1.4em; + vertical-align: middle; +} + +.markdown-body .contains-task-list:dir(rtl) .task-list-item-checkbox { + margin: 0 -1.6em .25em .2em; +} + +.markdown-body .contains-task-list { + position: relative; +} + +.markdown-body .contains-task-list:hover .task-list-item-convert-container, +.markdown-body .contains-task-list:focus-within .task-list-item-convert-container { + display: block; + width: auto; + height: 24px; + overflow: visible; + clip: auto; +} + +.markdown-body ::-webkit-calendar-picker-indicator { + filter: invert(50%); +} diff --git a/src/assets/css/highlight.scss b/src/assets/css/highlight.scss new file mode 100644 index 0000000..446a1e2 --- /dev/null +++ b/src/assets/css/highlight.scss @@ -0,0 +1,206 @@ +html.dark { + pre code.hljs { + display: block; + overflow-x: auto; + padding: 1em + } + + code.hljs { + padding: 3px 5px + } + + .hljs { + color: #abb2bf; + background: #282c34 + } + + .hljs-keyword, + .hljs-operator, + .hljs-pattern-match { + color: #f92672 + } + + .hljs-function, + .hljs-pattern-match .hljs-constructor { + color: #61aeee + } + + .hljs-function .hljs-params { + color: #a6e22e + } + + .hljs-function .hljs-params .hljs-typing { + color: #fd971f + } + + .hljs-module-access .hljs-module { + color: #7e57c2 + } + + .hljs-constructor { + color: #e2b93d + } + + .hljs-constructor .hljs-string { + color: #9ccc65 + } + + .hljs-comment, + .hljs-quote { + color: #b18eb1; + font-style: italic + } + + .hljs-doctag, + .hljs-formula { + color: #c678dd + } + + .hljs-deletion, + .hljs-name, + .hljs-section, + .hljs-selector-tag, + .hljs-subst { + color: #e06c75 + } + + .hljs-literal { + color: #56b6c2 + } + + .hljs-addition, + .hljs-attribute, + .hljs-meta .hljs-string, + .hljs-regexp, + .hljs-string { + color: #98c379 + } + + .hljs-built_in, + .hljs-class .hljs-title, + .hljs-title.class_ { + color: #e6c07b + } + + .hljs-attr, + .hljs-number, + .hljs-selector-attr, + .hljs-selector-class, + .hljs-selector-pseudo, + .hljs-template-variable, + .hljs-type, + .hljs-variable { + color: #d19a66 + } + + .hljs-bullet, + .hljs-link, + .hljs-meta, + .hljs-selector-id, + .hljs-symbol, + .hljs-title { + color: #61aeee + } + + .hljs-emphasis { + font-style: italic + } + + .hljs-strong { + font-weight: 700 + } + + .hljs-link { + text-decoration: underline + } +} + +html { + pre code.hljs { + display: block; + overflow-x: auto; + padding: 1em + } + + code.hljs { + padding: 3px 5px; + &::-webkit-scrollbar { + height: 4px; + } + } + + .hljs { + color: #383a42; + background: #fafafa + } + + .hljs-comment, + .hljs-quote { + color: #a0a1a7; + font-style: italic + } + + .hljs-doctag, + .hljs-formula, + .hljs-keyword { + color: #a626a4 + } + + .hljs-deletion, + .hljs-name, + .hljs-section, + .hljs-selector-tag, + .hljs-subst { + color: #e45649 + } + + .hljs-literal { + color: #0184bb + } + + .hljs-addition, + .hljs-attribute, + .hljs-meta .hljs-string, + .hljs-regexp, + .hljs-string { + color: #50a14f + } + + .hljs-attr, + .hljs-number, + .hljs-selector-attr, + .hljs-selector-class, + .hljs-selector-pseudo, + .hljs-template-variable, + .hljs-type, + .hljs-variable { + color: #986801 + } + + .hljs-bullet, + .hljs-link, + .hljs-meta, + .hljs-selector-id, + .hljs-symbol, + .hljs-title { + color: #4078f2 + } + + .hljs-built_in, + .hljs-class .hljs-title, + .hljs-title.class_ { + color: #c18401 + } + + .hljs-emphasis { + font-style: italic + } + + .hljs-strong { + font-weight: 700 + } + + .hljs-link { + text-decoration: underline + } +} diff --git a/src/assets/css/logo.svg b/src/assets/css/logo.svg new file mode 100644 index 0000000..7565660 --- /dev/null +++ b/src/assets/css/logo.svg @@ -0,0 +1 @@ + diff --git a/src/assets/css/main.css b/src/assets/css/main.css new file mode 100644 index 0000000..13e9739 --- /dev/null +++ b/src/assets/css/main.css @@ -0,0 +1,66 @@ +@import './base.css'; +@import './highlight.scss'; +@import './github-markdown.scss'; + +html, +body { + overflow: visible; + overflow-x: hidden; +} +#app { + height: 100%; + width: 100%; +} + +::-webkit-scrollbar { + width: 7px; + height: 8px; +} + +::-webkit-scrollbar-track { + background-color: #0000000d; +} + +::-webkit-scrollbar-thumb { + border-radius: 2px; + background-color: #9093994d; + box-shadow: inset 0 0 6px #0003; +} + +::-webkit-scrollbar-thumb:hover { + background-color: #b6b7b9; +} + +/* #app { + max-width: 1280px; + margin: 0 auto; + padding: 2rem; + + font-weight: normal; +} + +a, +.green { + text-decoration: none; + color: hsla(160, 100%, 37%, 1); + transition: 0.4s; +} + +@media (hover: hover) { + a:hover { + background-color: hsla(160, 100%, 37%, 0.2); + } +} + +@media (min-width: 1024px) { + body { + display: flex; + place-items: center; + } + + #app { + display: grid; + grid-template-columns: 1fr 1fr; + padding: 0 2rem; + } +} */ diff --git a/src/assets/css/mixin.scss b/src/assets/css/mixin.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/components/BackPage/index.vue b/src/components/BackPage/index.vue new file mode 100644 index 0000000..753703e --- /dev/null +++ b/src/components/BackPage/index.vue @@ -0,0 +1,23 @@ + + diff --git a/src/components/ScrollContainer/index.vue b/src/components/ScrollContainer/index.vue new file mode 100644 index 0000000..1a6d178 --- /dev/null +++ b/src/components/ScrollContainer/index.vue @@ -0,0 +1,93 @@ + + + + diff --git a/src/components/ScrollContainer/useScrollTo.js b/src/components/ScrollContainer/useScrollTo.js new file mode 100644 index 0000000..8b88232 --- /dev/null +++ b/src/components/ScrollContainer/useScrollTo.js @@ -0,0 +1,54 @@ +import { isFunction, isUnDef } from '@/utils/is.js' +import { ref, unref } from 'vue' + + + +const easeInOutQuad = (t, b, c, d) => { + t /= d / 2 + if (t < 1) { + return (c / 2) * t * t + b + } + t-- + return (-c / 2) * (t * (t - 2) - 1) + b +} +const move = (el, amount) => { + el.scrollTop = amount +} + +const position = (el) => { + return el.scrollTop +} +export function useScrollTo({ el, to, duration = 500, callback }) { + const isActiveRef = ref(false) + const start = position(el) + const change = to - start + const increment = 20 + let currentTime = 0 + duration = isUnDef(duration) ? 500 : duration + + const animateScroll = function () { + if (!unref(isActiveRef)) { + return + } + currentTime += increment + const val = easeInOutQuad(currentTime, start, change, duration) + move(el, val) + if (currentTime < duration && unref(isActiveRef)) { + requestAnimationFrame(animateScroll) + } else { + if (callback && isFunction(callback)) { + callback() + } + } + } + const run = () => { + isActiveRef.value = true + animateScroll() + } + + const stop = () => { + isActiveRef.value = false + } + + return { start: run, stop } +} diff --git a/src/components/Scrollbar/bar.js b/src/components/Scrollbar/bar.js new file mode 100644 index 0000000..363e7f0 --- /dev/null +++ b/src/components/Scrollbar/bar.js @@ -0,0 +1,109 @@ +import { + defineComponent, + h, + computed, + ref, + getCurrentInstance, + onUnmounted, + inject, +} from 'vue'; +import { on, off } from '@/utils/domUtils'; + +import { renderThumbStyle, BAR_MAP } from './util'; + +export default defineComponent({ + name: 'Bar', + + props: { + vertical: Boolean, + size: String, + move: Number, + }, + + setup(props) { + const instance = getCurrentInstance(); + const thumb = ref(); + const wrap = inject('scroll-bar-wrap', {}) ; + const bar = computed(() => { + return BAR_MAP[props.vertical ? 'vertical' : 'horizontal']; + }); + const barStore = ref({}); + const cursorDown = ref(); + const clickThumbHandler = (e) => { + // prevent click event of right button + if (e.ctrlKey || e.button === 2) { + return; + } + window.getSelection()?.removeAllRanges(); + startDrag(e); + barStore.value[bar.value.axis] = + e.currentTarget[bar.value.offset] - + (e[bar.value.client] - e.currentTarget.getBoundingClientRect()[bar.value.direction]); + }; + + const clickTrackHandler = (e) => { + const offset = Math.abs( + e.target.getBoundingClientRect()[bar.value.direction] - e[bar.value.client], + ); + const thumbHalf = thumb.value[bar.value.offset] / 2; + const thumbPositionPercentage = + ((offset - thumbHalf) * 100) / instance?.vnode.el?.[bar.value.offset]; + + wrap.value[bar.value.scroll] = + (thumbPositionPercentage * wrap.value[bar.value.scrollSize]) / 100; + }; + const startDrag = (e) => { + e.stopImmediatePropagation(); + cursorDown.value = true; + on(document, 'mousemove', mouseMoveDocumentHandler); + on(document, 'mouseup', mouseUpDocumentHandler); + document.onselectstart = () => false; + }; + + const mouseMoveDocumentHandler = (e) => { + if (cursorDown.value === false) return; + const prevPage = barStore.value[bar.value.axis]; + + if (!prevPage) return; + + const offset = + (instance?.vnode.el?.getBoundingClientRect()[bar.value.direction] - e[bar.value.client]) * + -1; + const thumbClickPosition = thumb.value[bar.value.offset] - prevPage; + const thumbPositionPercentage = + ((offset - thumbClickPosition) * 100) / instance?.vnode.el?.[bar.value.offset]; + wrap.value[bar.value.scroll] = + (thumbPositionPercentage * wrap.value[bar.value.scrollSize]) / 100; + }; + + function mouseUpDocumentHandler() { + cursorDown.value = false; + barStore.value[bar.value.axis] = 0; + off(document, 'mousemove', mouseMoveDocumentHandler); + document.onselectstart = null; + } + + onUnmounted(() => { + off(document, 'mouseup', mouseUpDocumentHandler); + }); + + return () => + h( + 'div', + { + class: ['scrollbar__bar', 'is-' + bar.value.key], + onMousedown: clickTrackHandler, + }, + h('div', { + ref: thumb, + class: 'scrollbar__thumb', + onMousedown: clickThumbHandler, + style: renderThumbStyle({ + size: props.size, + move: props.move, + bar: bar.value, + }), + }), + ); + }, +}); diff --git a/src/components/Scrollbar/index.vue b/src/components/Scrollbar/index.vue new file mode 100644 index 0000000..6a8d8ab --- /dev/null +++ b/src/components/Scrollbar/index.vue @@ -0,0 +1,215 @@ + + + \ No newline at end of file diff --git a/src/components/Scrollbar/util.js b/src/components/Scrollbar/util.js new file mode 100644 index 0000000..e9ac558 --- /dev/null +++ b/src/components/Scrollbar/util.js @@ -0,0 +1,50 @@ + +export const BAR_MAP = { + vertical: { + offset: 'offsetHeight', + scroll: 'scrollTop', + scrollSize: 'scrollHeight', + size: 'height', + key: 'vertical', + axis: 'Y', + client: 'clientY', + direction: 'top', + }, + horizontal: { + offset: 'offsetWidth', + scroll: 'scrollLeft', + scrollSize: 'scrollWidth', + size: 'width', + key: 'horizontal', + axis: 'X', + client: 'clientX', + direction: 'left', + }, +}; + +// @ts-ignore +export function renderThumbStyle({ move, size, bar }) { + const style = {}; + const translate = `translate${bar.axis}(${move}%)`; + + style[bar.size] = size; + style.transform = translate; + style.msTransform = translate; + style.webkitTransform = translate; + + return style; +} + +function extend(to, _from) { + return Object.assign(to, _from); +} + +export function toObject(arr) { + const res = {}; + for (let i = 0; i < arr.length; i++) { + if (arr[i]) { + extend(res, arr[i]); + } + } + return res; +} diff --git a/src/components/SvgIcon/index.vue b/src/components/SvgIcon/index.vue new file mode 100644 index 0000000..61cb0ab --- /dev/null +++ b/src/components/SvgIcon/index.vue @@ -0,0 +1,57 @@ + + + diff --git a/src/config/host.config.js b/src/config/host.config.js new file mode 100644 index 0000000..1ec17fd --- /dev/null +++ b/src/config/host.config.js @@ -0,0 +1,3 @@ +const hostAPI = 'http://test-admin.haituaigc.com'; + +export default hostAPI; \ No newline at end of file diff --git a/src/icons/index.js b/src/icons/index.js new file mode 100644 index 0000000..77235b6 --- /dev/null +++ b/src/icons/index.js @@ -0,0 +1,6 @@ + +import SvgIcon from '@/components/SvgIcon/index.vue'// svg component + +export function registerSvgIcon(app) { + app.component(SvgIcon.name, SvgIcon); +} \ No newline at end of file diff --git a/src/icons/svg/arrow-right.svg b/src/icons/svg/arrow-right.svg new file mode 100644 index 0000000..eb46519 --- /dev/null +++ b/src/icons/svg/arrow-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/back.svg b/src/icons/svg/back.svg new file mode 100644 index 0000000..a791bc5 --- /dev/null +++ b/src/icons/svg/back.svg @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/src/icons/svg/close.svg b/src/icons/svg/close.svg new file mode 100644 index 0000000..37089b0 --- /dev/null +++ b/src/icons/svg/close.svg @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/src/icons/svg/cloud-upload.svg b/src/icons/svg/cloud-upload.svg new file mode 100644 index 0000000..5211914 --- /dev/null +++ b/src/icons/svg/cloud-upload.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/delete.svg b/src/icons/svg/delete.svg new file mode 100644 index 0000000..b6eb71e --- /dev/null +++ b/src/icons/svg/delete.svg @@ -0,0 +1,18 @@ + + + + + + + + \ No newline at end of file diff --git a/src/icons/svg/generated.svg b/src/icons/svg/generated.svg new file mode 100644 index 0000000..97feda6 --- /dev/null +++ b/src/icons/svg/generated.svg @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/src/icons/svg/pause.svg b/src/icons/svg/pause.svg new file mode 100644 index 0000000..ad06619 --- /dev/null +++ b/src/icons/svg/pause.svg @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/src/icons/svg/refresh.svg b/src/icons/svg/refresh.svg new file mode 100644 index 0000000..ce002a2 --- /dev/null +++ b/src/icons/svg/refresh.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/icons/svg/right-arrow.svg b/src/icons/svg/right-arrow.svg new file mode 100644 index 0000000..46e1f35 --- /dev/null +++ b/src/icons/svg/right-arrow.svg @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/src/icons/svg/send.svg b/src/icons/svg/send.svg new file mode 100644 index 0000000..66b57d8 --- /dev/null +++ b/src/icons/svg/send.svg @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/src/icons/svg/stop.svg b/src/icons/svg/stop.svg new file mode 100644 index 0000000..a6e5160 --- /dev/null +++ b/src/icons/svg/stop.svg @@ -0,0 +1,9 @@ + + + + + \ No newline at end of file diff --git a/src/icons/svg/t.svg b/src/icons/svg/t.svg new file mode 100644 index 0000000..ba0b603 --- /dev/null +++ b/src/icons/svg/t.svg @@ -0,0 +1,6 @@ + + + \ No newline at end of file diff --git a/src/icons/svg/收起箭头小2.svg b/src/icons/svg/收起箭头小2.svg new file mode 100644 index 0000000..caf97c1 --- /dev/null +++ b/src/icons/svg/收起箭头小2.svg @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/src/icons/svg/政治.svg b/src/icons/svg/政治.svg new file mode 100644 index 0000000..393547c --- /dev/null +++ b/src/icons/svg/政治.svg @@ -0,0 +1,6 @@ + + + diff --git a/src/icons/svg/法律法规.svg b/src/icons/svg/法律法规.svg new file mode 100644 index 0000000..a7b32c4 --- /dev/null +++ b/src/icons/svg/法律法规.svg @@ -0,0 +1,6 @@ + + + diff --git a/src/icons/svg/行业竞争力.svg b/src/icons/svg/行业竞争力.svg new file mode 100644 index 0000000..25aec57 --- /dev/null +++ b/src/icons/svg/行业竞争力.svg @@ -0,0 +1,6 @@ + + + diff --git a/src/icons/svg/预测服务.svg b/src/icons/svg/预测服务.svg new file mode 100644 index 0000000..78ecb01 --- /dev/null +++ b/src/icons/svg/预测服务.svg @@ -0,0 +1,15 @@ + + + + + + + \ No newline at end of file diff --git a/src/icons/svgo.yml b/src/icons/svgo.yml new file mode 100644 index 0000000..d11906a --- /dev/null +++ b/src/icons/svgo.yml @@ -0,0 +1,22 @@ +# replace default config + +# multipass: true +# full: true + +plugins: + + # - name + # + # or: + # - name: false + # - name: true + # + # or: + # - name: + # param1: 1 + # param2: 2 + +- removeAttrs: + attrs: + - 'fill' + - 'fill-rule' diff --git a/src/io/cache.js b/src/io/cache.js new file mode 100755 index 0000000..94dbb9a --- /dev/null +++ b/src/io/cache.js @@ -0,0 +1,34 @@ +/** + * [本地缓存] + * @Author: Fu Xiaochun + * @Email: f2e.xiaochun@gmail.com + */ + + +function factory(engine){ + return { + set: (key, data)=>{ + if(!key){ return; } + engine.setItem(key, JSON.stringify(data)); + }, + get: (key)=>{ + if(!key){ return; } + let data = engine.getItem(key); + try { + return JSON.parse(data); + } catch (error) { + return data; + } + }, + remove: (key)=>{ + if(!key){ return; } + engine.removeItem(key); + }, + clear: ()=>{ + engine.clear(); + } + } +} + +export const localCache = factory(localStorage); +export const sessionCache = factory(sessionStorage); \ No newline at end of file diff --git a/src/io/http.js b/src/io/http.js new file mode 100755 index 0000000..c3ebf5d --- /dev/null +++ b/src/io/http.js @@ -0,0 +1,56 @@ +/** + * [axios封装] + * @Author: Fu Xiaochun + * @Email: f2e.xiaochun@gmail.com + */ + +import axios from 'axios'; + +const http = (url = '', data = {}, type = 'POST', otherConfig = {}) => { + let config = Object.assign({ isLoading: true, timeout: 10000 }, otherConfig); + let promise; + type = type.toUpperCase(); + + return new Promise((resolve, reject) => { + if (type === 'GET') { + promise = axios({ + method: type, + url, + params: data, + timeout: config.timeout + }); + } else if (['POST', 'DELETE', 'PUT', 'PATCH'].includes(type)) { + promise = axios({ + method: type, + url, + headers: { + 'Content-Type': 'application/json; charset=UTF-8', + 'Accept': 'application/json; charset=UTF-8', + 'isLoading': config.isLoading, + }, + data: data, + timeout: config.timeout + }); + } else { + promise = Promise.reject('请求方法入参错误:', type); + } + + promise.then((response) => { + if (response && response.status >= 200 && response.status < 300 && response.data.status == 0) { + resolve(response.data); + } else { + if(response && response.data && response.data.status == 401){ + return false; + }else if (response && response.data) { + reject({ ...response.data, message: response.data.message ? response.data.message : response.data.msg }); + } else { + reject('当前系统繁忙,请稍后再试'); + } + } + }).catch((error) => { + reject(error); + }); + }); +}; + +export default http; diff --git a/src/io/httpConfig.js b/src/io/httpConfig.js new file mode 100755 index 0000000..c52b58a --- /dev/null +++ b/src/io/httpConfig.js @@ -0,0 +1,96 @@ +/** + * [axios配置] + * @Author: Fu Xiaochun + * @Email: f2e.xiaochun@gmail.com + */ + +import axios from 'axios'; +import { localCache } from './cache'; +import router from "@/router"; +import hostAPI from '@/config/host.config' +import { showToast } from 'vant'; + +export default function () { + let _token = ''; + let requestCount = 0;//请求数量 + + // axios.defaults.baseURL = '//' + window.location.host; + axios.defaults.baseURL = hostAPI; + + // 请求超时时间为10秒 + axios.defaults.timeout = 10000; + + // 请求发送拦截,并在头部加入token + axios.interceptors.request.use( + function (config) { + + let nextToken = localCache.get('auth') && localCache.get('auth').token; + let toeknType = localCache.get('auth') && localCache.get('auth').token_type; + if (config.url.indexOf('/auth/login') > -1) { + // 如果为登录接口,重置登录信息 + _token = ''; + } else if (_token == '') { + // 第一次登录直接从缓存后去token + _token = nextToken; + } else { + // 前后两次调用token不同,退出登录防止串token + _token = _token != nextToken ? '' : nextToken; + } + if (_token) { + config.headers['Authorization'] = `${toeknType} ${_token}`; // 存在将token写入请求头 + } + // if (config.headers.isLoading !== false) showLoading(); + return config; + }, + function (error) { + // if (error.config.headers.isLoading !== false) hideLoading(); + return Promise.reject(error); + } + ); + + // 请求结果拦截,根据不同的错误码触发相应操作 + axios.interceptors.response.use( + function (response) { + try { + if (response.data.status != 0) { + if (response.data.status == 401 ) { + // token失效 + showToast('账号过期或异地登录, 请重新登录'); + localCache.remove('auth'); + localCache.remove('userInfo'); + window.location.pathname='/home'; + // router.replace({name: 'Home', params: {auth: 'over'}}); + } + } + } catch (e) { + showToast('后台' + response.data.status + '错误返回格式不正确'); + } + // if (response.config.headers.isLoading !== false) hideLoading(); + return response; + }, + function (error) { + // if (error.config.headers.isLoading !== false) hideLoading(); + if (error.response) { + switch (error.response.data.status) { + case 401: + // token失效 + showToast('账号过期或异地登录, 请重新登录'); + localCache.remove('auth'); + localCache.remove('userInfo'); + window.location.pathname='/home'; + break; + case 500: + // 500 服务端请求错误 + showToast('接口500错误:【' + error.response.data.path + '】'); + return Promise.reject(error.response); + case 404: + // 找不到资源 + showToast('接口404错误:【' + error.response.data.path + '】'); + return Promise.reject(error.response); + default: + return Promise.reject(error.response); + } + } + } + ); +} diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..a2cdcc8 --- /dev/null +++ b/src/main.js @@ -0,0 +1,24 @@ +import "./assets/css/main.css"; +import 'virtual:svg-icons-register'; +import 'virtual:windi.css' + +import { createApp } from "vue"; +import { createPinia } from "pinia"; + +import App from "./App.vue"; +import router from "./router"; +import { registerSvgIcon } from './icons/index.js' +import httpConfig from "./io/httpConfig"; +import 'vant/es/toast/style'; + + +httpConfig(); + +const app = createApp(App); + +registerSvgIcon(app); + +app.use(createPinia()); +app.use(router); + +app.mount("#app"); diff --git a/src/router/index.js b/src/router/index.js new file mode 100644 index 0000000..e7d7acf --- /dev/null +++ b/src/router/index.js @@ -0,0 +1,22 @@ +import { createRouter, createWebHistory } from "vue-router"; + +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes: [ + { + path: "/", + name: "Layout", + redirect: "/home", + children: [{ + path: "home", + name: "Home", + mate: { + title: "首页-AI助理", + }, + component: () => import("@/views/home/index.vue"), + }] + } + ], +}); + +export default router; diff --git a/src/stores/authModal.js b/src/stores/authModal.js new file mode 100644 index 0000000..d424a9c --- /dev/null +++ b/src/stores/authModal.js @@ -0,0 +1,18 @@ +import { ref, computed } from "vue"; +import { defineStore } from "pinia"; + +export const useAuthModal = defineStore("authModal", () => { + const isShow = ref(false); + const authModalType = ref('login'); + function showAuthModal() { + isShow.value = true; + } + function hideAuthModal(){ + isShow.value = false; + } + function setAuthModalType(type){ + authModalType.value = type; + } + + return { isShow, authModalType, showAuthModal, hideAuthModal, setAuthModalType }; +}); diff --git a/src/stores/userInfo.js b/src/stores/userInfo.js new file mode 100644 index 0000000..f3253c5 --- /dev/null +++ b/src/stores/userInfo.js @@ -0,0 +1,11 @@ +import { ref, computed } from "vue"; +import { defineStore } from "pinia"; + +export const useUserInfo = defineStore("userInfo", () => { + const userData = ref({}); + function updateUserInfo(data) { + userData.value = data; + } + + return { userData, updateUserInfo }; +}); diff --git a/src/utils/copy.js b/src/utils/copy.js new file mode 100644 index 0000000..80a6a7f --- /dev/null +++ b/src/utils/copy.js @@ -0,0 +1,18 @@ +export function copyToClip(text) { + return new Promise((resolve, reject) => { + try { + const input = document.createElement('textarea') + input.setAttribute('readonly', 'readonly') + input.value = text + document.body.appendChild(input) + input.select() + if (document.execCommand('copy')) + document.execCommand('copy') + document.body.removeChild(input) + resolve(text) + } + catch (error) { + reject(error) + } + }) +} diff --git a/src/utils/domUtils.js b/src/utils/domUtils.js new file mode 100644 index 0000000..909bc50 --- /dev/null +++ b/src/utils/domUtils.js @@ -0,0 +1,172 @@ + +import { upperFirst } from 'lodash-es' + + +export function getBoundingClientRect(element) { + if (!element || !element.getBoundingClientRect) { + return 0 + } + return element.getBoundingClientRect() +} + +function trim(string) { + return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, '') +} + +/* istanbul ignore next */ +export function hasClass(el, cls) { + if (!el || !cls) return false + if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.') + if (el.classList) { + return el.classList.contains(cls) + } else { + return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1 + } +} + +/* istanbul ignore next */ +export function addClass(el, cls) { + if (!el) return + let curClass = el.className + const classes = (cls || '').split(' ') + + for (let i = 0, j = classes.length; i < j; i++) { + const clsName = classes[i] + if (!clsName) continue + + if (el.classList) { + el.classList.add(clsName) + } else if (!hasClass(el, clsName)) { + curClass += ' ' + clsName + } + } + if (!el.classList) { + el.className = curClass + } +} + +/* istanbul ignore next */ +export function removeClass(el, cls) { + if (!el || !cls) return + const classes = cls.split(' ') + let curClass = ' ' + el.className + ' ' + + for (let i = 0, j = classes.length; i < j; i++) { + const clsName = classes[i] + if (!clsName) continue + + if (el.classList) { + el.classList.remove(clsName) + } else if (hasClass(el, clsName)) { + curClass = curClass.replace(' ' + clsName + ' ', ' ') + } + } + if (!el.classList) { + el.className = trim(curClass) + } +} +/** + * Get the left and top offset of the current element + * left: the distance between the leftmost element and the left side of the document + * top: the distance from the top of the element to the top of the document + * right: the distance from the far right of the element to the right of the document + * bottom: the distance from the bottom of the element to the bottom of the document + * rightIncludeBody: the distance between the leftmost element and the right side of the document + * bottomIncludeBody: the distance from the bottom of the element to the bottom of the document + * + * @description: + */ +export function getViewportOffset(element) { + const doc = document.documentElement + + const docScrollLeft = doc.scrollLeft + const docScrollTop = doc.scrollTop + const docClientLeft = doc.clientLeft + const docClientTop = doc.clientTop + + const pageXOffset = window.pageXOffset + const pageYOffset = window.pageYOffset + + const box = getBoundingClientRect(element) + + const { left: retLeft, top: rectTop, width: rectWidth, height: rectHeight } = box + + const scrollLeft = (pageXOffset || docScrollLeft) - (docClientLeft || 0) + const scrollTop = (pageYOffset || docScrollTop) - (docClientTop || 0) + const offsetLeft = retLeft + pageXOffset + const offsetTop = rectTop + pageYOffset + + const left = offsetLeft - scrollLeft + const top = offsetTop - scrollTop + + const clientWidth = window.document.documentElement.clientWidth + const clientHeight = window.document.documentElement.clientHeight + return { + left: left, + top: top, + right: clientWidth - rectWidth - left, + bottom: clientHeight - rectHeight - top, + rightIncludeBody: clientWidth - left, + bottomIncludeBody: clientHeight - top, + } +} + +export function hackCss(attr, value) { + const prefix = ['webkit', 'Moz', 'ms', 'OT'] + + const styleObj = {} + prefix.forEach((item) => { + styleObj[`${item}${upperFirst(attr)}`] = value + }) + return { + ...styleObj, + [attr]: value, + } +} + +/* istanbul ignore next */ +export function on( + element, + event, + handler, +) { + if (element && event && handler) { + element.addEventListener(event, handler, false) + } +} + +/* istanbul ignore next */ +export function off( + element, + event, + handler, +) { + if (element && event && handler) { + element.removeEventListener(event, handler, false) + } +} + +/* istanbul ignore next */ +export function once(el, event, fn) { + const listener = function (self, ...args) { + if (fn) { + fn.apply(this, args) + } + off(el, event, listener) + } + on(el, event, listener) +} + +export function useRafThrottle(fn) { + let locked = false + // @ts-ignore + return function (...args) { + if (locked) return + locked = true + window.requestAnimationFrame(() => { + // @ts-ignore + fn.apply(this, args) + locked = false + }) + } +} diff --git a/src/utils/event.js b/src/utils/event.js new file mode 100644 index 0000000..e17f153 --- /dev/null +++ b/src/utils/event.js @@ -0,0 +1,42 @@ +import ResizeObserver from 'resize-observer-polyfill' + +const isServer = typeof window === 'undefined' + +/* istanbul ignore next */ +function resizeHandler(entries) { + for (const entry of entries) { + const listeners = entry.target.__resizeListeners__ || [] + if (listeners.length) { + listeners.forEach((fn) => { + fn() + }) + } + } +} + +/* istanbul ignore next */ +export function addResizeListener(element, fn) { + if (isServer) return + if (!element.__resizeListeners__) { + element.__resizeListeners__ = [] + element.__ro__ = new ResizeObserver(resizeHandler) + element.__ro__.observe(element) + } + element.__resizeListeners__.push(fn) +} + +/* istanbul ignore next */ +export function removeResizeListener(element, fn) { + if (!element || !element.__resizeListeners__) return + element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1) + if (!element.__resizeListeners__.length) { + element.__ro__.disconnect() + } +} + +export function triggerWindowResize() { + const event = document.createEvent('HTMLEvents') + event.initEvent('resize', true, true) + ;(event).eventType = 'message' + window.dispatchEvent(event) +} diff --git a/src/utils/is.js b/src/utils/is.js new file mode 100644 index 0000000..2ee71a6 --- /dev/null +++ b/src/utils/is.js @@ -0,0 +1,105 @@ +const toString = Object.prototype.toString + +export function is(val, type) { + return toString.call(val) === `[object ${type}]` +} + +export function isDef(val) { + return typeof val !== 'undefined' +} + +export function isUnDef(val) { + return !isDef(val) +} + +export function isObject(val) { + return val !== null && is(val, 'Object') +} + +export function isEmpty(val) { + if (isArray(val) || isString(val)) { + return val.length === 0 + } + + if (val instanceof Map || val instanceof Set) { + return val.size === 0 + } + + if (isObject(val)) { + return Object.keys(val).length === 0 + } + + return false +} + +export function isDate(val) { + return is(val, 'Date') +} + +export function isNull(val) { + return val === null +} + +export function isNullAndUnDef(val) { + return isUnDef(val) && isNull(val) +} + +export function isNullOrUnDef(val) { + return isUnDef(val) || isNull(val) +} + +export function isNumber(val) { + return is(val, 'Number') +} + +export function isPromise(val) { + return is(val, 'Promise') && isObject(val) && isFunction(val.then) && isFunction(val.catch) +} + +export function isString(val) { + return is(val, 'String') +} + +export function isFunction(val) { + return typeof val === 'function' +} + +export function isBoolean(val) { + return is(val, 'Boolean') +} + +export function isRegExp(val) { + return is(val, 'RegExp') +} + +export function isArray(val) { + return val && Array.isArray(val) +} + +export function isWindow(val) { + return typeof window !== 'undefined' && is(val, 'Window') +} + +export function isElement(val) { + return isObject(val) && !!val.tagName +} + +export function isMap(val) { + return is(val, 'Map') +} + +export const isServer = typeof window === 'undefined' + +export const isClient = !isServer + +export function isUrl(path) { + const reg = + /^(((^https?:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+(?::\d+)?|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?(\/#\/)?(?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)$/ + return reg.test(path) +} +/** + * 验证手机格式 + */ +export function isMobile(value) { + return /^1[3-9]\d{9}$/.test(value) +} diff --git a/src/views/home/index.vue b/src/views/home/index.vue new file mode 100644 index 0000000..5aed8cc --- /dev/null +++ b/src/views/home/index.vue @@ -0,0 +1,19 @@ + + + + + \ No newline at end of file diff --git a/vite.config.js b/vite.config.js new file mode 100644 index 0000000..64653ed --- /dev/null +++ b/vite.config.js @@ -0,0 +1,58 @@ +import { fileURLToPath, URL } from 'node:url' + +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import vueJsx from '@vitejs/plugin-vue-jsx' +import WindiCSS from 'vite-plugin-windicss' + +import Components from 'unplugin-vue-components/vite'; +import { VantResolver } from 'unplugin-vue-components/resolvers'; + +const path = require('path') +import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'; +import hostAPI from './src/config/host.config' + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [ + vue(), + vueJsx(), + WindiCSS(), + createSvgIconsPlugin({ + iconDirs: [path.resolve(process.cwd(), 'src/icons/svg')], + symbolId: 'icon-[name]', + }), + Components({ + resolvers: [ + VantResolver({ + importStyle: false, // css in js + }), + ], + }), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)) + } + }, + css: { + preprocessorOptions: { + //define global scss variable + scss: { + additionalData: `@import "@/assets/css/mixin.scss";` + } + } + }, + server: { + host: 'localhost', + port: '8080', + open: false, + proxy: { + '/api': { + target: hostAPI, + changeOrigin: true, + // rewrite: (path) => path.replace(/^\/api/, ''), + }, + } + }, +}) diff --git a/windi.config.js b/windi.config.js new file mode 100644 index 0000000..8b9c7a7 --- /dev/null +++ b/windi.config.js @@ -0,0 +1,8 @@ +export default { + extend: { + + }, + plugins: [ + require('windicss/plugin/line-clamp'), + ], +} \ No newline at end of file