first commit

This commit is contained in:
编码猿
2024-09-27 02:06:13 +08:00
commit 852d94fbb9
36760 changed files with 3274413 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
> 1%
last 2 versions
not dead

View File

@@ -0,0 +1,23 @@
.DS_Store
node_modules
/dist
# local env files
.env.local
.env.*.local
# Log files
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

View File

@@ -0,0 +1,25 @@
module.exports = {
"plugins": {
"postcss-import": {},
"postcss-url": {},
// to edit target browsers: use "browserslist" field in package.json
"autoprefixer": {
browsers: ['Android >= 4.0', 'iOS >= 7'],
overrideBrowserslist: [
"Android 4.1",
"iOS 7.1",
"Chrome > 31",
"ff > 31",
"ie >= 8"
//'last 10 versions', // 所有主流浏览器最近10版本用
],
grid: true
},
"postcss-pxtorem": {
"rootValue": 37.5,
"propList": [
"*"
]
}
}
}

View File

@@ -0,0 +1,23 @@
# vuecli3-tpl
## Project setup
```
npm install
```
### Compiles and hot-reloads for development
```
npm run serve
```
### Compiles and minifies for production
```
npm run build
```
### Customize configuration
See [Configuration Reference](https://cli.vuejs.org/config/).

View File

@@ -0,0 +1,5 @@
module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
]
}

View File

@@ -0,0 +1,34 @@
{
"name": "vuecli3-tpl",
"version": "0.1.0",
"private": true,
"scripts": {
"start": "vue-cli-service serve",
"build": "vue-cli-service build"
},
"dependencies": {
"amfe-flexible": "^2.2.1",
"axios": "^0.24.0",
"core-js": "^3.6.5",
"node-rsa": "^1.1.1",
"vant": "^2.12.34",
"vue": "^2.6.11",
"vue-router": "^3.2.0"
},
"devDependencies": {
"@vue/cli-plugin-babel": "~4.5.0",
"@vue/cli-plugin-router": "~4.5.0",
"@vue/cli-service": "~4.5.0",
"less": "^3.0.4",
"less-loader": "^5.0.0",
"postcss-import": "^11.0.0",
"postcss-loader": "^2.0.8",
"postcss-pxtorem": "^5.0.0",
"postcss-url": "^7.2.1",
"pug": "^3.0.2",
"pug-html-loader": "^1.1.5",
"pug-plain-loader": "^1.1.0",
"style-resources-loader": "^1.4.1",
"vue-template-compiler": "^2.6.11"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 703 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 983 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 646 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 952 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 910 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 865 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta content="IE=edge" http-equiv="X-UA-Compatible">
<meta content="width=device-width,initial-scale=1.0" name="viewport">
<link href="<%= BASE_URL %>favicon.ico" rel="icon">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>

View File

@@ -0,0 +1,9 @@
<template>
<div id="app">
<router-view/>
</div>
</template>
<style lang="less">
</style>

View File

@@ -0,0 +1,6 @@
@import "./config/color.less";
@import "./config/size.less";
@import "./mixins/mixins.less";
@import "./mixins/normalize.less";
@import "./mixins/resetUI.less";

View File

@@ -0,0 +1,3 @@
@defaultSize: 14px;
@smallSize: 12px;
@bigSize_19: 19px;

View File

@@ -0,0 +1,270 @@
.transform(@t) {
-webkit-transform: @t;
transform: @t;
}
.flex-shrink(@fs) {
-webkit-box-flex: @fs;
-webkit-flex-shrink: @fs;
-ms-flex: 0 @fs auto;
flex-shrink: @fs;
}
.clearfix() {
&:after,
&:before {
content: " ";
display: table;
}
&:after {
clear: both;
}
}
.hairline(@position, @color) when (@position = top) {
&:before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: auto;
right: auto;
height: 1px;
width: 100%;
background-color: @color;
display: block;
z-index: 15;
// .transform-origin(50% 0%);
html.pixel-ratio-2 & {
.transform(scaleY(0.5));
}
html.pixel-ratio-3 & {
.transform(scaleY(0.33));
}
}
}
.hairline(@position, @color) when (@position = left) {
&:before {
content: '';
position: absolute;
left: 0;
top: 0;
bottom: auto;
right: auto;
width: 1px;
height: 100%;
background-color: @color;
display: block;
z-index: 15;
// .transform-origin(0% 50%);
html.pixel-ratio-2 & {
.transform(scaleX(0.5));
}
html.pixel-ratio-3 & {
.transform(scaleX(0.33));
}
}
}
.hairline(@position, @color) when (@position = bottom) {
&:after {
content: '';
position: absolute;
left: 0;
bottom: 0;
right: auto;
top: auto;
height: 1px;
width: 100%;
background-color: @color;
display: block;
z-index: 15;
html.pixel-ratio-2 & {
.transform(scaleY(0.5));
}
html.pixel-ratio-3 & {
.transform(scaleY(0.33));
}
}
}
.hairline(@position, @color) when (@position = right) {
&:after {
content: '';
position: absolute;
right: 0;
top: 0;
left: auto;
bottom: auto;
width: 1px;
height: 100%;
background-color: @color;
display: block;
z-index: 15;
// .transform-origin(100% 50%);
html.pixel-ratio-2 & {
.transform(scaleX(0.5));
}
html.pixel-ratio-3 & {
.transform(scaleX(0.33));
}
}
}
// For left and top
.hairline-color(@position, @color) when not (@position = right) and not (@position = bottom) {
&:before {
background-color: @color;
}
}
// Shadow
.depth(@level:1) {
& when (@level = 0) {
box-shadow: none;
}
& when (@level = 1) {
box-shadow: 0 2px 1px -1px rgba(0, 0, 0, .2), 0 1px 1px 0 rgba(0, 0, 0, .14), 0 1px 3px 0 rgba(0, 0, 0, .12);
}
& when (@level = 2) {
box-shadow: 0 3px 1px -2px rgba(0, 0, 0, .2), 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12);
}
& when (@level = 3) {
box-shadow: 0 3px 3px -2px rgba(0, 0, 0, .2), 0 3px 4px 0 rgba(0, 0, 0, .14), 0 1px 8px 0 rgba(0, 0, 0, .12);
}
& when (@level = 4) {
box-shadow: 0 2px 4px -1px rgba(0, 0, 0, .2), 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12);
}
& when (@level = 5) {
box-shadow: 0 3px 5px -1px rgba(0, 0, 0, .2), 0 5px 8px 0 rgba(0, 0, 0, .14), 0 1px 14px 0 rgba(0, 0, 0, .12);
}
& when (@level = 6) {
box-shadow: 0 3px 5px -1px rgba(0, 0, 0, .2), 0 6px 10px 0 rgba(0, 0, 0, .14), 0 1px 18px 0 rgba(0, 0, 0, .12);
}
& when (@level = 7) {
box-shadow: 0 4px 5px -2px rgba(0, 0, 0, .2), 0 7px 10px 1px rgba(0, 0, 0, .14), 0 2px 16px 1px rgba(0, 0, 0, .12);
}
& when (@level = 8) {
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, .2), 0 8px 10px 1px rgba(0, 0, 0, .14), 0 3px 14px 2px rgba(0, 0, 0, .12);
}
& when (@level = 9) {
box-shadow: 0 5px 6px -3px rgba(0, 0, 0, .2), 0 9px 12px 1px rgba(0, 0, 0, .14), 0 3px 16px 2px rgba(0, 0, 0, .12);
}
& when (@level = 10) {
box-shadow: 0 6px 6px -3px rgba(0, 0, 0, .2), 0 10px 14px 1px rgba(0, 0, 0, .14), 0 4px 18px 3px rgba(0, 0, 0, .12);
}
& when (@level = 11) {
box-shadow: 0 6px 7px -4px rgba(0, 0, 0, .2), 0 11px 15px 1px rgba(0, 0, 0, .14), 0 4px 20px 3px rgba(0, 0, 0, .12);
}
& when (@level = 12) {
box-shadow: 0 7px 8px -4px rgba(0, 0, 0, .2), 0 12px 17px 2px rgba(0, 0, 0, .14), 0 5px 22px 4px rgba(0, 0, 0, .12);
}
& when (@level = 13) {
box-shadow: 0 7px 8px -4px rgba(0, 0, 0, .2), 0 13px 19px 2px rgba(0, 0, 0, .14), 0 5px 24px 4px rgba(0, 0, 0, .12);
}
& when (@level = 14) {
box-shadow: 0 7px 9px -4px rgba(0, 0, 0, .2), 0 14px 21px 2px rgba(0, 0, 0, .14), 0 5px 26px 4px rgba(0, 0, 0, .12);
}
& when (@level = 15) {
box-shadow: 0 8px 9px -5px rgba(0, 0, 0, .2), 0 15px 22px 2px rgba(0, 0, 0, .14), 0 6px 28px 5px rgba(0, 0, 0, .12);
}
& when (@level = 16) {
box-shadow: 0 8px 10px -5px rgba(0, 0, 0, .2), 0 16px 24px 2px rgba(0, 0, 0, .14), 0 6px 30px 5px rgba(0, 0, 0, .12);
}
& when (@level = 17) {
box-shadow: 0 8px 11px -5px rgba(0, 0, 0, .2), 0 17px 26px 2px rgba(0, 0, 0, .14), 0 6px 32px 5px rgba(0, 0, 0, .12);
}
& when (@level = 18) {
box-shadow: 0 9px 11px -5px rgba(0, 0, 0, .2), 0 18px 28px 2px rgba(0, 0, 0, .14), 0 7px 34px 6px rgba(0, 0, 0, .12);
}
& when (@level = 19) {
box-shadow: 0 9px 12px -6px rgba(0, 0, 0, .2), 0 19px 29px 2px rgba(0, 0, 0, .14), 0 7px 36px 6px rgba(0, 0, 0, .12);
}
& when (@level = 20) {
box-shadow: 0 10px 13px -6px rgba(0, 0, 0, .2), 0 20px 31px 3px rgba(0, 0, 0, .14), 0 8px 38px 7px rgba(0, 0, 0, .12);
}
& when (@level = 21) {
box-shadow: 0 10px 13px -6px rgba(0, 0, 0, .2), 0 21px 33px 3px rgba(0, 0, 0, .14), 0 8px 40px 7px rgba(0, 0, 0, .12);
}
& when (@level = 22) {
box-shadow: 0 10px 14px -6px rgba(0, 0, 0, .2), 0 22px 35px 3px rgba(0, 0, 0, .14), 0 8px 42px 7px rgba(0, 0, 0, .12);
}
& when (@level = 23) {
box-shadow: 0 11px 14px -7px rgba(0, 0, 0, .2), 0 23px 36px 3px rgba(0, 0, 0, .14), 0 9px 44px 8px rgba(0, 0, 0, .12);
}
& when (@level = 24) {
box-shadow: 0 11px 15px -7px rgba(0, 0, 0, .2), 0 24px 38px 3px rgba(0, 0, 0, .14), 0 9px 46px 8px rgba(0, 0, 0, .12);
}
// & when (@level = 1) {
// box-shadow: rgba(0, 0, 0, 0.117647) 0px 1px 6px, rgba(0, 0, 0, 0.117647) 0px 1px 4px;
// }
// & when (@level = 2) {
// box-shadow: rgba(0, 0, 0, 0.156863) 0px 3px 10px, rgba(0, 0, 0, 0.227451) 0px 3px 10px;
// }
// & when (@level = 3) {
// box-shadow: rgba(0, 0, 0, 0.188235) 0px 10px 30px, rgba(0, 0, 0, 0.227451) 0px 6px 10px;
// }
// & when (@level = 4) {
// box-shadow: rgba(0, 0, 0, 0.247059) 0px 14px 45px, rgba(0, 0, 0, 0.219608) 0px 10px 18px;
// }
// & when (@level = 5) {
// box-shadow: rgba(0, 0, 0, 0.298039) 0px 19px 60px, rgba(0, 0, 0, 0.219608) 0px 15px 20px;
// }
}
// Highlighted Links
.active-highlight(@color:rgba(255, 255, 255, 0.15)) {
&:before {
content: '';
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
background-color: @color;
background-repeat: no-repeat;
background-position: center;
background-size: 100% 100%;
opacity: 0;
pointer-events: none;
.transition(600ms);
}
&.active-state:before,
html:not(.watch-active-state) &:active:before {
opacity: 1;
.transition(150ms);
}
}
.active-highlight-color(@color) {
&:before {
background-image: -webkit-radial-gradient(center, circle cover, @color 66%, rgba(red(@color), green(@color), blue(@color), 0) 66%);
background-image: radial-gradient(circle at center, @color 66%, rgba(red(@color), green(@color), blue(@color), 0) 66%);
}
}
// No Scrollbar
.no-scrollbar() {
&::-webkit-scrollbar {
display: none !important;
width: 0 !important;
height: 0 !important;
-webkit-appearance: none;
opacity: 0 !important;
}
}
.ellipsis() {
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
word-wrap: break-word;
}

View File

@@ -0,0 +1,426 @@
/*! normalize.css v4.1.1 | MIT License | github.com/necolas/normalize.css */
/**
* 1. Change the default font family in all browsers (opinionated).
* 2. Prevent adjustments of font size after orientation changes in IE and iOS.
*/
html {
font-family: sans-serif; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
}
/**
* Remove the margin in all browsers (opinionated).
*/
.content {
margin-top: 45px;
margin-bottom: 50px;
}
input {
outline: none;
border: none;
}
body,h1,h2,h3,h4,h5,h6,ul,li,p{
margin: 0;
}
/* HTML5 display definitions
========================================================================== */
/**
* Add the correct display in IE 9-.
* 1. Add the correct display in Edge, IE, and Firefox.
* 2. Add the correct display in IE.
*/
article,
aside,
details, /* 1 */
figcaption,
figure,
footer,
header,
main, /* 2 */
menu,
nav,
section,
summary { /* 1 */
display: block;
}
/**
* Add the correct display in IE 9-.
*/
audio,
canvas,
progress,
video {
display: inline-block;
}
/**
* Add the correct display in iOS 4-7.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Add the correct vertical alignment in Chrome, Firefox, and Opera.
*/
progress {
vertical-align: baseline;
}
/**
* Add the correct display in IE 10-.
* 1. Add the correct display in IE.
*/
template, /* 1 */
[hidden] {
display: none;
}
/* Links
========================================================================== */
/**
* 1. Remove the gray background on active links in IE 10.
* 2. Remove gaps in links underline in iOS 8+ and Safari 8+.
*/
a {
background-color: transparent; /* 1 */
-webkit-text-decoration-skip: objects; /* 2 */
}
/**
* Remove the outline on focused links when they are also active or hovered
* in all browsers (opinionated).
*/
a:active,
a:hover {
outline-width: 0;
}
/* Text-level semantics
========================================================================== */
/**
* 1. Remove the bottom border in Firefox 39-.
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
*/
abbr[title] {
border-bottom: none; /* 1 */
text-decoration: underline; /* 2 */
text-decoration: underline dotted; /* 2 */
}
/**
* Prevent the duplicate application of `bolder` by the next rule in Safari 6.
*/
b,
strong {
font-weight: inherit;
}
/**
* Add the correct font weight in Chrome, Edge, and Safari.
*/
b,
strong {
font-weight: bolder;
}
/**
* Add the correct font style in Android 4.3-.
*/
dfn {
font-style: italic;
}
/**
* Correct the font size and margin on `h1` elements within `section` and
* `article` contexts in Chrome, Firefox, and Safari.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
/**
* Add the correct background and color in IE 9-.
*/
mark {
background-color: #ff0;
color: #000;
}
/**
* Add the correct font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` elements from affecting the line height in
* all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
/* Embedded content
========================================================================== */
/**
* Remove the border on images inside links in IE 10-.
*/
img {
border-style: none;
}
/**
* Hide the overflow in IE.
*/
svg:not(:root) {
overflow: hidden;
}
/* Grouping content
========================================================================== */
/**
* 1. Correct the inheritance and scaling of font size in all browsers.
* 2. Correct the odd `em` font sizing in all browsers.
*/
code,
kbd,
pre,
samp {
font-family: monospace, monospace; /* 1 */
font-size: 1em; /* 2 */
}
/**
* Add the correct margin in IE 8.
*/
figure {
margin: 1em 40px;
}
/**
* 1. Add the correct box sizing in Firefox.
* 2. Show the overflow in Edge and IE.
*/
hr {
box-sizing: content-box; /* 1 */
height: 0; /* 1 */
overflow: visible; /* 2 */
}
/* Forms
========================================================================== */
/**
* 1. Change font properties to `inherit` in all browsers (opinionated).
* 2. Remove the margin in Firefox and Safari.
*/
button,
input,
select,
textarea {
font: inherit; /* 1 */
margin: 0; /* 2 */
}
/**
* Restore the font weight unset by the previous rule.
*/
optgroup {
font-weight: bold;
}
/**
* Show the overflow in IE.
* 1. Show the overflow in Edge.
*/
button,
input { /* 1 */
overflow: visible;
}
/**
* Remove the inheritance of text transform in Edge, Firefox, and IE.
* 1. Remove the inheritance of text transform in Firefox.
*/
button,
select { /* 1 */
text-transform: none;
}
/**
* 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
* controls in Android 4.
* 2. Correct the inability to style clickable types in iOS and Safari.
*/
button,
html [type="button"], /* 1 */
[type="reset"],
[type="submit"] {
-webkit-appearance: button; /* 2 */
}
/**
* Remove the inner border and padding in Firefox.
*/
button::-moz-focus-inner,
[type="button"]::-moz-focus-inner,
[type="reset"]::-moz-focus-inner,
[type="submit"]::-moz-focus-inner {
border-style: none;
padding: 0;
}
/**
* Restore the focus styles unset by the previous rule.
*/
button:-moz-focusring,
[type="button"]:-moz-focusring,
[type="reset"]:-moz-focusring,
[type="submit"]:-moz-focusring {
outline: 1px dotted ButtonText;
}
/**
* Change the border, margin, and padding in all browsers (opinionated).
*/
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
/**
* 1. Correct the text wrapping in Edge and IE.
* 2. Correct the color inheritance from `fieldset` elements in IE.
* 3. Remove the padding so developers are not caught out when they zero out
* `fieldset` elements in all browsers.
*/
legend {
box-sizing: border-box; /* 1 */
color: inherit; /* 2 */
display: table; /* 1 */
max-width: 100%; /* 1 */
padding: 0; /* 3 */
white-space: normal; /* 1 */
}
/**
* Remove the default vertical scrollbar in IE.
*/
textarea {
overflow: auto;
}
/**
* 1. Add the correct box sizing in IE 10-.
* 2. Remove the padding in IE 10-.
*/
[type="checkbox"],
[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
}
/**
* Correct the cursor style of increment and decrement buttons in Chrome.
*/
[type="number"]::-webkit-inner-spin-button,
[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Correct the odd appearance in Chrome and Safari.
* 2. Correct the outline style in Safari.
*/
[type="search"] {
-webkit-appearance: textfield; /* 1 */
outline-offset: -2px; /* 2 */
}
/**
* Remove the inner padding and cancel buttons in Chrome and Safari on OS X.
*/
[type="search"]::-webkit-search-cancel-button,
[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* Correct the text style of placeholders in Chrome, Edge, and Safari.
*/
::-webkit-input-placeholder {
color: inherit;
opacity: 0.54;
}
/**
* 1. Correct the inability to style clickable types in iOS and Safari.
* 2. Change font properties to `inherit` in Safari.
*/
::-webkit-file-upload-button {
-webkit-appearance: button; /* 1 */
font: inherit; /* 2 */
}

View File

@@ -0,0 +1,38 @@
.home {
.search {
display: flex;
align-items: center;
justify-content: space-between;
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 45px;
padding: 0 15px;
box-sizing: border-box;
background: #fff;
z-index: 999;
.van-search {
flex: 1;
padding: 0 0.32rem !important;
}
img {
width: 0.66667rem;
height: 0.42667rem;
}
}
.content {
.van-image {
width: 0.85333rem;
}
.ad {
margin-top: 20px;
img {
width: 100%;
}
}
.hf {
width: 100%;
}
}
}

View File

@@ -0,0 +1,55 @@
.Login {
padding-left: 1.027rem;
padding-right: 1rem;
padding-top: 1.867rem;
h2 {
font-size: 0.926rem;
color: #000000;
margin-bottom: 2.707rem;
}
.user_input {
input {
width: 100%;
height: 40px;
background-repeat: no-repeat !important;
border-bottom: 0.027rem solid #ccc;
font-size: 0.333rem;
color: #c2bebe;
padding-left: 0.76rem;
background-position: left center !important;
box-sizing: border-box;
}
.user_name {
background: url("/img/name.png");
background-size: 0.347rem 0.4rem;
margin-bottom: 0.567rem;
}
.user_pwd {
background: url("/img/pwd.png");
background-size: 0.347rem 0.4rem;
margin-bottom: 0.827rem;
}
}
.submit {
width: 7.973rem;
height: 1.333rem;
background-image: linear-gradient(268deg, #42e57b 0%,#42e97d 25%,#3fee9b 50%,#37f9d6 100%),
linear-gradient(#42e97d,#42e97d);
background-blend-mode: normal,normal;
border-radius: 0.662rem;
text-align: center;
line-height: 1.333rem;
color: #fff;
font-size: 0.426rem;
margin-bottom: 0.827rem;
}
.tips {
font-size: 0.333rem;
color: #7b7a7a;
text-align: right;
span {
font-size: 0.333rem;
color: #42e97d !important;
}
}
}

View File

@@ -0,0 +1,8 @@
@import "../_.less";
.about {
h2 {
color: @themeColor;
font-size: @bigSize_19;
}
}

View File

@@ -0,0 +1,34 @@
<template>
<div class="hello">
<h1>{{ msg }}</h1>
</div>
</template>
<script>
export default {
name: 'HelloWorld',
props: {
msg: String
}
}
</script>
<style lang="less" scoped>
h3 {
margin: 40px 0 0;
}
ul {
list-style-type: none;
padding: 0;
}
li {
display: inline-block;
margin: 0 10px;
}
a {
color: #42b983;
}
</style>

View File

@@ -0,0 +1,30 @@
<template lang="pug">
van-tabbar(v-model='active' route active-color="#42e97d")
van-tabbar-item(icon='home-o' to="/home" ) 首页
van-tabbar-item(icon='shopping-cart-o' to="/car" ) 购物车
van-tabbar-item(icon='apps-o' to="/type" ) 分类
van-tabbar-item(icon='contact' to="/me" ) 我的
</template>
<script>
export default {
name: 'Nav',
data() {
return {
active: 0
}
},
created() {
},
methods: {
async getIndex() {
}
},
components: {}
}
</script>
<style lang="less" scoped>
</style>

View File

@@ -0,0 +1,59 @@
<template lang="pug">
.ShopItem
van-row()
van-col(span='12' v-for="(item,index) in list" :key="index")
img(:src="item.img")
h3.title {{ item.title }}
p.desc {{ item.desc }}
p.pice {{ item.pice }}
</template>
<script>
export default {
name: 'ShopItem',
props: {
list: {
type: Array,
default: () => []
}
},
data() {
return {}
},
created() {
},
methods: {
async getIndex() {
}
},
components: {}
}
</script>
<style lang="less" scoped>
.ShopItem {
.van-col {
text-align: center;
margin-bottom: 15px;
img {
width: 100%;
}
.title {
font-size: 0.37333rem;
color: #000;
}
.desc {
color: rgba(0,0,0,0.54);
font-size: 0.32rem;
margin-top: 0.08333rem;
}
.pice {
color: #ea625b;
font-size: 0.37333rem;
margin-top: 0.13333rem;
}
}
}
</style>

View File

@@ -0,0 +1,39 @@
<template lang="pug">
.Swiper
van-swipe(:autoplay='3000', indicator-color='white')
van-swipe-item(v-for="(item,index) in list" :key="index")
slot(:item='item')
</template>
<script>
export default {
name: 'Swiper',
props: {
list: {
type: Array,
default: () => []
}
},
data() {
return {}
},
created() {
},
methods: {
async getIndex() {
}
},
components: {}
}
</script>
<style lang="less" scoped>
.van-swipe {
/deep/ img {
width: 100%;
}
}
</style>

View File

@@ -0,0 +1,48 @@
import Vant from 'vant';
import 'vant/lib/index.css';
import Swiper from "@/components/Swiper";
import ShopItem from "@/components/ShopItem";
import http from "@/service";
import utils from "@/utils";
export default {
devBaseUrl: 'http://127.0.0.1:9090', // 开发阶段
testBaseUrl: '', // 测试阶段
prodBaseUrl: '', // 正式阶段
apiList: {
home: '/home/index',
login: '/user/login',
add: '/user/add'
},
VuePlugins: [Vant],
VueComponents: [ Swiper, ShopItem ],
NotVuePlugins: [
{n: '$http', v: http},
{n: '$utils', v: utils},
],
CheckBaseUrl: function () {
switch (process.env.NODE_ENV) {
case "development":
return this.devBaseUrl;
break;
case "test":
return this.testBaseUrl;
break;
case "production":
return this.prodBaseUrl;
break;
default:
break;
}
},
rsa_public_key: `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9eo8WIbWS5Yql06imlhrW0ZXh
faivPavdULvYLIxIKyUaOwMPFrPuHqqBNGnYOpiPHAKL+zxk2j4u+6jhB6VK1SOD
ccSLxIRxd0HmSDS+hBzYRf4vKc8BLlhMrYhnLmcxCc+PJIIa4DfCZnu8FfQlu/5L
ljjpYN9kHOpHAT+xpQIDAQAB
-----END PUBLIC KEY-----`
}

View File

@@ -0,0 +1,100 @@
import axios from "axios";
import rsa from "@/utils/rsa"
import config from "@/config"
import {Toast, Dialog} from 'vant';
export default class Http {
constructor() {
this.instance = axios.create({
baseURL: config.CheckBaseUrl(),
timeout: 10000,
headers: {
"Content-Type": "application/json; charset=utf-8"
}
});
this.interceptors();
}
async get(params) {
return await this.instance.get(params.url, {
// params: params.data,
headers: Object.assign({
data: new rsa(config).PublicKeyEncryption(params.data),
token: localStorage.getItem("token")
}, params.headers)
})
}
async post(params) {
return await this.instance.post(params.url, null,{
headers: Object.assign({
data: new rsa(config).PublicKeyEncryption(params.data),
token: localStorage.getItem("token")
}, params.headers)
})
}
interceptors() {
// 添加请求拦截器
this.instance.interceptors.request.use(function (config) {
Toast.loading({
duration: 0,
message: '加载中...'
})
return config;
}, function (error) {
// 对请求错误做些什么
return Promise.reject(error);
});
// 添加响应拦截器
this.instance.interceptors.response.use(function (response) {
if (response.data.hasOwnProperty("result") && response.data.result != null) {
response.data.result = new rsa(config).PublicKeyDecryption(response.data.result)
}
Toast.clear()
switch (response.data.status) {
case 200:
return response.data.result
break;
case 501:
Dialog.alert({
title: '温馨提示',
message: response.data.message,
}).then(() => {
location.href = "/#/login"
});
break;
case 500:
Toast.fail({
duration: 3000,
message: response.data.message
})
throw new Error(response.data.message);
break;
case 404:
Toast.fail({
duration: 3000,
message: response.data.message
})
throw new Error(response.data.message);
break;
default:
break;
}
return response.data;
}, function (error) {
// 对响应错误做点什么
return Promise.reject(error);
});
}
}

View File

@@ -0,0 +1,20 @@
import "amfe-flexible"
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import config from "@/config";
Vue.config.productionTip = false
// 初始化vue插件
config.VuePlugins.forEach(v => Vue.use(v));
config.VueComponents.forEach(v => Vue.component(v.name, v));
// 挂载自定义方法到vue实例上,实现全局访问
config.NotVuePlugins.forEach(v => Vue.prototype[v["n"]] = v["v"]);
new Vue({
router,
render: h => h(App)
}).$mount('#app')

View File

@@ -0,0 +1,96 @@
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
const routes = [
{
path: '/login',
name: 'login',
component: () => import(/* webpackChunkName: "login" */ '../views/User/Login'),
meta: {
isLogin: false,
title: '登录'
}
},
{
path: '/reg',
name: 'reg',
component: () => import(/* webpackChunkName: "reg" */ '../views/User/Reg'),
meta: {
isLogin: false,
title: '注册'
}
},
{
path: '/',
component: () => import(/* webpackChunkName: "layout" */ '../views/layout'),
children: [
{
path: '/home',
name: 'home',
component: () => import(/* webpackChunkName: "home" */ '../views/Home'),
meta: {
isLogin: true,
title: '首页'
}
},
{
path: '/car',
name: 'car',
component: () => import(/* webpackChunkName: "car" */ '../views/Car'),
meta: {
isLogin: true,
title: '购物车'
}
},
{
path: '/type',
name: 'type',
component: () => import(/* webpackChunkName: "type" */ '../views/Type'),
meta: {
isLogin: true,
title: '分类'
}
},
{
path: '/me',
name: 'me',
component: () => import(/* webpackChunkName: "me" */ '../views/Me'),
meta: {
isLogin: true,
title: '我的'
}
}
]
}
]
const router = new VueRouter({
routes
})
// 实现页面的权限控制(有些页面需要登录才可以访问)
router.beforeEach((to, from, next) => {
document.title = to.meta.title
if (to.meta.isLogin) {
if (localStorage.getItem("token") != null) {
next();
} else {
next({
path: '/login',
query: {
from: to.fullPath
}
})
}
} else {
next();
}
})
export default router

View File

@@ -0,0 +1,20 @@
import Http from "@/http";
import config from "@/config"
export default class UserService {
async login(data = {}, headers = {}) {
return await (new Http()).post({
url: config.apiList.login,
data: data,
headers: headers
})
}
async add(data = {}, headers = {}) {
return await (new Http()).post({
url: config.apiList.add,
data: data,
headers: headers
})
}
}

View File

@@ -0,0 +1,3 @@
export default class carService {
}

View File

@@ -0,0 +1,11 @@
// 统一导出
import indexService from "@/service/indexService";
import carService from "@/service/carService";
import userService from "@/service/UserService";
export default {
index: new indexService(),
car: new carService(),
user: new userService(),
}

View File

@@ -0,0 +1,13 @@
import Http from "@/http";
import config from "@/config"
export default class indexService {
async home(data = {}, headers = {}) {
return await (new Http()).post({
url: config.apiList.home,
data: data,
headers: headers
})
}
}

View File

@@ -0,0 +1,14 @@
class utils {
test() {
console.log("工具函数");
}
checkPhone(phoneNumber) {
return /^[1][3,4,5,7,8,9][0-9]{9}$/.test(phoneNumber);
}
}
export default new utils();

View File

@@ -0,0 +1,18 @@
import NodeRSA from "node-rsa";
class Rsa {
constructor (config) {
this.public_key = config.rsa_public_key
}
// 公钥加密
PublicKeyEncryption(text) {
return (new NodeRSA(this.public_key)).encrypt(JSON.stringify(text), 'base64')
}
// 公钥解密
PublicKeyDecryption(text) {
return JSON.parse((new NodeRSA(this.public_key)).decryptPublic(text, 'utf8'))
}
}
export default Rsa;

View File

@@ -0,0 +1,23 @@
<template lang="pug">
.Car
h2 Car
</template>
<script>
export default {
name: 'Car',
created() {
},
methods: {
async getIndex() {
}
},
components: {}
}
</script>
<style lang="less" scoped>
@import "~@page/Car.less";
</style>

View File

@@ -0,0 +1,77 @@
<template lang="pug">
.home
.search
img(src="/img/logo.png")
van-search(v-model='value', shape='round', placeholder='请输入搜索关键词')
van-icon(name="manager-o")
.content
Swiper(:list="SwiperList")
template(v-slot:default='{ item }')
img(:src="item")
van-grid(:border="false")
van-grid-item(v-for="(item,index) in typeList" :text='item.title' :key="index")
template(v-slot:icon)
van-image(:src='item.icon')
van-row.ad
van-col(span='12')
img(src="https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/32b5d24417b673008f386592c4d17046.jpg?thumb=1&w=358&h=508")
van-col(span='12')
van-row
van-col(span='24')
img(src="https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/1480d862e1f5a41e5adae8c030eef511.jpg?thumb=1&w=358&h=252")
van-col(span='24')
img(src="https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/1480d862e1f5a41e5adae8c030eef511.jpg?thumb=1&w=358&h=252")
img.hf(src="https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/3ca39ff880dfbcbc0e45314782c39fff.jpg?thumb=1&w=720&h=280")
ShopItem(:list="ShopList")
</template>
<script>
import HelloWorld from '@/components/HelloWorld.vue'
export default {
name: 'Home',
data() {
return {
SwiperList: [
'https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/bb4a8b7d9e77567c7330776a866e717f.jpg?thumb=1&w=720&h=360',
'https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/0b2bb13c396cc6205dd91da3a91a275a.jpg?thumb=1&w=720&h=360',
'https://cdn.cnbj1.fds.api.mi-img.com/mi-mall/69d599cf6d4f0188312f4386b8bfd093.jpeg?thumb=1&w=720&h=360'
],
typeList: [
{ title: '限时白嫖', icon: '/img/type_1.png', id: 1 },
{ title: '新品推荐', icon: '/img/type_2.png', id: 2 },
{ title: '低价高配', icon: '/img/type_3.png', id: 3 },
{ title: '超值特卖', icon: '/img/type_4.png', id: 4 },
],
ShopList: [
{ title: '华为荣耀20', desc: '荣耀20 李现同款 ..', pice: '3000' , img: 'https://img.alicdn.com/imgextra/i1/2838892713/O1CN01waq2hb1Vub5zMArfX_!!2838892713.png_2200x2200Q100s50.jpg_.webp' },
{ title: '华为荣耀20', desc: '荣耀20 李现同款 ..', pice: '3000' , img: 'https://img.alicdn.com/imgextra/i1/2838892713/O1CN01waq2hb1Vub5zMArfX_!!2838892713.png_2200x2200Q100s50.jpg_.webp' },
{ title: '华为荣耀20', desc: '荣耀20 李现同款 ..', pice: '3000' , img: 'https://img.alicdn.com/imgextra/i1/2838892713/O1CN01waq2hb1Vub5zMArfX_!!2838892713.png_2200x2200Q100s50.jpg_.webp' },
{ title: '华为荣耀20', desc: '荣耀20 李现同款 ..', pice: '3000' , img: 'https://img.alicdn.com/imgextra/i1/2838892713/O1CN01waq2hb1Vub5zMArfX_!!2838892713.png_2200x2200Q100s50.jpg_.webp' },
{ title: '华为荣耀20', desc: '荣耀20 李现同款 ..', pice: '3000' , img: 'https://img.alicdn.com/imgextra/i1/2838892713/O1CN01waq2hb1Vub5zMArfX_!!2838892713.png_2200x2200Q100s50.jpg_.webp' },
]
}
},
created() {
this.getIndex();
},
methods: {
async getIndex() {
let res = await this.$http.index.home({
id: 1,
page: 2
});
console.log(res);
}
},
components: {
HelloWorld
}
}
</script>
<style lang="less" scoped>
@import "~@page/Home.less";
</style>

View File

@@ -0,0 +1,23 @@
<template lang="pug">
.Me
h2 Me
</template>
<script>
export default {
name: 'Me',
created() {
},
methods: {
async getIndex() {
}
},
components: {}
}
</script>
<style lang="less" scoped>
@import "~@page/Me.less";
</style>

View File

@@ -0,0 +1,23 @@
<template lang="pug">
.Type
h2 Type
</template>
<script>
export default {
name: 'Type',
created() {
},
methods: {
async getIndex() {
}
},
components: {}
}
</script>
<style lang="less" scoped>
//@import "~@page/Type.less";
</style>

View File

@@ -0,0 +1,100 @@
<template lang="pug">
.Login
h2 {{ status ? '登 录' : '注 册' }}
.user_input
.login(v-if="status" )
input.user_name(placeholder="用户名" type="text" v-model="loginParams.name")
input.user_pwd(placeholder="密码" type="password" v-model="loginParams.pwd")
.reg(v-else)
input.user_pwd(placeholder="手机号" type="number" v-model="regParams.phone")
input.user_name(placeholder="用户名" type="text" v-model="regParams.name")
input.user_pwd(placeholder="密码" type="password" v-model="regParams.pwd")
.submit(@click="status ? UserLogin() : UserReg()") {{ status ? '登 录' : '注 册' }}
.tips
| {{ status ? '没有账号?' : '已有账号?' }}
span(@click="status = !status") 立刻{{ status ? '注册' : '登录' }}
</template>
<script>
export default {
name: 'Login',
data() {
return {
status: true, // true 登录 false 注册
loginParams: {
name: 'lb',
pwd: '1234567890'
},
regParams: {
name: '',
pwd: '',
phone: ''
}
}
},
created() {
},
methods: {
async UserLogin() {
if (this.loginParams.name.length === 0) {
this.$toast("用户名不能为空")
return false;
}
if (this.loginParams.pwd.length === 0) {
this.$toast("密码不能为空")
return false;
}
let res = await this.$http.user.login(this.loginParams);
console.log(res)
localStorage.setItem("token", res.token)
this.$toast.success({
message: '恭喜,登录成功!',
forbidClick: true,
onClose: () => {
this.$router.replace("/home")
}
})
},
async UserReg() {
if (!this.$utils.checkPhone(this.regParams.phone)) {
this.$toast("手机号不正确")
return false;
}
if (this.regParams.name.length === 0) {
this.$toast("用户名不能为空")
return false;
}
if (this.regParams.pwd.length === 0) {
this.$toast("密码不能为空")
return false;
}
let res = await this.$http.user.add(this.regParams);
this.$toast.success({
message: '恭喜,注册成功!',
forbidClick: true,
onClose: () => {
this.loginParams.name = this.regParams.name
this.loginParams.pwd = this.regParams.pwd
this.status = true
}
})
}
},
components: {}
}
</script>
<style lang="less" scoped>
@import "~@page/Login.less";
</style>

View File

@@ -0,0 +1,23 @@
<template lang="pug">
.Reg
h2 Reg
</template>
<script>
export default {
name: 'Reg',
created() {
},
methods: {
async getIndex() {
}
},
components: {}
}
</script>
<style lang="less" scoped>
@import "~@page/Reg.less";
</style>

View File

@@ -0,0 +1,27 @@
<template lang="pug">
.layout
router-view
Nav
</template>
<script>
import Nav from "@/components/Nav";
export default {
name: 'layout',
created() {
},
methods: {
async getIndex() {
}
},
components: {
Nav
}
}
</script>
<style lang="less" scoped>
</style>

View File

@@ -0,0 +1,50 @@
const path = require("path");
module.exports = {
publicPath: "./",
productionSourceMap: false,
chainWebpack: config => {
// 移除 prefetch 插件
config.plugins.delete('prefetch')
config.plugins.delete('preload')
// 配置全局css变量
const types = ['vue-modules', 'vue', 'normal-modules', 'normal']
types.forEach(type => addStyleResource(config.module.rule('less').oneOf(type)))
// 配置路径别名
config.resolve.alias
//第一个参数:别名 第二个参数:路径
.set('@', resolve('src'))
.set('@page', resolve('src/assets/less/page'))
.set('@less', resolve('src/assets/less'))
// 配置pug
config.module.rule('pug')
.test(/\.pug$/)
.use('pug-html-loader')
.loader('pug-html-loader')
.end()
}
}
function addStyleResource(rule) {
rule.use('style-resource')
.loader('style-resources-loader')
.options({
patterns: [
path.resolve(__dirname, './src/assets/less/_.less'),
],
})
}
function resolve(dir) {
return path.join(__dirname, dir) //path.join(_dirname)设置绝对路径
}

View File

@@ -0,0 +1,53 @@
json web token
jwt
ajax 请求是无状态的
RSA 非对称加密
公钥
私钥
token: WEWE.WF.REG.45.Y.4.6.7.U.T.JTYJ.TYJTYJTYJTYJYTJTYJYT.J.TJ.TYJ.TY.JTY
{
id: 1,
page: 2
}
KFEJWEHFBERUHGERGHETHRTHRTHR.HJR.H.RYJ.TY.JTU.KJT.UJ.TY.JTY.
{
status: 200,
data: [],
message: "1111"
}
WHDVQWDVUQWVDQWBFJQEBIFEFWGFR/GERGTEHRTHRYHRDHREHREHERHETH.EHRTHRTRH/HRHRTHRTHRT
http://127.0.0.1/api/index?id=1&page=3&time=16633444&sign=4bf8eb636c8981b361bcc03394f6ef06
time: 时间戳
sign:加密参数 规则
1 先排序
2 格式化字符串,做成get请求参数的格式
3 MD5加密 (对用户注册的密码进行加密,加密不可解密的)
{
id: 1,
time: 16633444,
page: 3,
}
id=1&time=16633444&page=3
4bf8eb636c8981b361bcc03394f6ef06
支付(假的)
后面和你们说