├── .browserslistrc
├── .eslintrc.js
├── .gitignore
├── README.md
├── babel.config.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── public
├── favicon.ico
├── img
│ └── icons
│ │ ├── android-chrome-192x192.png
│ │ ├── android-chrome-512x512.png
│ │ ├── android-chrome-maskable-192x192.png
│ │ ├── android-chrome-maskable-512x512.png
│ │ ├── apple-touch-icon-120x120.png
│ │ ├── apple-touch-icon-152x152.png
│ │ ├── apple-touch-icon-180x180.png
│ │ ├── apple-touch-icon-60x60.png
│ │ ├── apple-touch-icon-76x76.png
│ │ ├── apple-touch-icon.png
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── msapplication-icon-144x144.png
│ │ ├── mstile-150x150.png
│ │ └── safari-pinned-tab.svg
├── index.html
└── robots.txt
├── src
├── App.vue
├── api
│ └── index.ts
├── assets
│ └── styles
│ │ ├── index.scss
│ │ ├── main.scss
│ │ ├── mixin.scss
│ │ └── reset.scss
├── components
│ ├── confirm
│ │ └── index.vue
│ ├── menu
│ │ ├── index.scss
│ │ └── index.vue
│ ├── modal
│ │ └── index.vue
│ ├── page-head
│ │ ├── assets
│ │ │ ├── index.scss
│ │ │ ├── left-normal.png
│ │ │ └── left-white.png
│ │ └── index.vue
│ ├── product-item
│ │ ├── index.scss
│ │ ├── index.vue
│ │ └── product_default.jpg
│ └── scroll
│ │ └── index.vue
├── config
│ └── index.ts
├── main.ts
├── mock
│ └── data.ts
├── registerServiceWorker.ts
├── router
│ └── index.ts
├── shims-tsx.d.ts
├── shims-vue.d.ts
├── store
│ ├── home
│ │ ├── index.ts
│ │ └── interface.ts
│ ├── index.ts
│ └── product
│ │ ├── index.ts
│ │ └── interface.ts
├── utils
│ └── http.ts
└── views
│ ├── home
│ ├── components
│ │ ├── floor
│ │ │ ├── index.scss
│ │ │ └── index.vue
│ │ └── swiper
│ │ │ └── swiper.vue
│ └── index.vue
│ ├── login
│ ├── index.scss
│ └── index.vue
│ ├── product-detail
│ ├── components
│ │ ├── detail-con.vue
│ │ └── head.vue
│ ├── index.scss
│ └── index.vue
│ ├── product-list
│ ├── component
│ │ ├── list-item
│ │ │ └── index.vue
│ │ ├── search-head
│ │ │ └── index.vue
│ │ └── select-tab
│ │ │ └── index.vue
│ ├── index.scss
│ └── index.vue
│ ├── profile
│ ├── component
│ │ ├── profile-foot
│ │ │ └── index.vue
│ │ └── profile-info
│ │ │ └── index.vue
│ ├── index.scss
│ └── index.vue
│ ├── register
│ ├── index.scss
│ └── index.vue
│ └── user
│ ├── components
│ ├── head-info
│ │ └── index.vue
│ └── tab-list
│ │ └── index.vue
│ ├── index.scss
│ └── index.vue
├── tsconfig.json
├── vue.config.js
└── yarn.lock
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 1%
2 | last 2 versions
3 | not dead
4 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | node: true
5 | },
6 | extends: [
7 | "plugin:vue/essential",
8 | "eslint:recommended",
9 | "@vue/typescript/recommended",
10 | "@vue/prettier",
11 | "@vue/prettier/@typescript-eslint"
12 | ],
13 | parserOptions: {
14 | ecmaVersion: 2020
15 | },
16 | rules: {
17 | "no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
18 | "no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off"
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 | pnpm-debug.log*
14 |
15 | # Editor directories and files
16 | .idea
17 | .vscode
18 | *.suo
19 | *.ntvs*
20 | *.njsproj
21 | *.sln
22 | *.sw?
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ### 使用ts对shop项目进行重构
2 |
3 |
4 | vue2 + vuex + vue-router + webpack + ES6/7 + axios + sass
5 |
6 | 框架:使用了vue全家桶进行开发,路由跳转使用的是vue-router,数据请求使用了官方推荐的axios插件,使用es6/7进行开发。
7 |
8 | 移动端适配: 由于是web-app,因此需要兼容不同设备的屏幕的大小,在这里使用的手淘推荐的[flexible方案](https://www.w3cplus.com/mobile/lib-flexible-for-html5-layout.html),通过动态的设置根元素的font-size大小,使用rem来进行移动端适配。在这里由于使用rem进行布局,而通常给我们的设计稿是640px,750px为标准的,在编写的时候把px大小转换为rem也比较麻烦,因此这里使用了postcss-px2rem,在编译的时候会将px自动转换为rem。
9 |
10 | css预处理器:目前流行的css预处理主要是stylus,less,sass,个人感觉less和sass差别不大,stylus缩进式语法有点不太习惯,综上选择了sass进行样式的编写,通过预处理器可以以编程的方式书写css代码,添加变量,函数,样式继承等。
11 |
12 | 后台接口:在这里使用的是慕课网提供的接口:[接口文档](https://gitee.com/imooccode/happymmallwiki/wikis/Home)
13 |
14 | 跨域处理:由于使用的外部接口,前端项目运行地址与接口访问地址不同,浏览器的同源策略使得我们不得不处理跨域,因此需要对跨域进行简单处理。
15 | 1. 开发模式下:需要在config下的index.js进行配置
16 | proxyTable: {
17 | '/api': {
18 | target: 'http://test.happymmall.com', //源地址
19 | changeOrigin: true, //改变源
20 | pathRewrite: {
21 | '^/api': '' //路径重写
22 | }
23 | }
24 | }
25 | ```
26 |
27 | 在进行接口请求时在接口路径前加/api即可,编译后会将/api重写为线上的接口地址
28 |
29 | 2. 生产模式下:在这里使用的是nignx,需要在远程服务器上安装nignx,然后在nginx.conf文件内配置location即可。
30 |
31 | # 功能介绍
32 |
33 | 在这里主要用vue是把之前慕课网上电商项目进行了重构,做了个移动版本的,功能基本相同,主要是包括4个模块:
34 |
35 | 用户模块:登录,注册,个人信息修改,密码找回,更新密码。
36 |
37 | 商品模块:首页,分类,搜索商品,商品详情
38 |
39 | 购物车模块:购物车商品增加,删除,全选,单选,多选
40 |
41 | 订单模块:包括地址的管理,提交订单,订单列表,详情,取消订单等
42 |
43 | 在这里本来想做支付模块,发现接口返回的二维码失效支付不了,因此只到支付详情这块。
44 |
45 |
46 | 后续:
47 |
48 | 1. 在这里只是简单实现了基本功能,当然作为web-app,用户体验是第一位的,后续会持续的对项目进行性能优化
49 | 2. 数据请求这块使用的axios插件,后续会用原生fecth进行实现
50 |
51 | #### 感觉不错的,反手就是一个赞👍,另外项目还要很多地方需要优化,欢迎大家issue!
52 |
53 |
54 | ## Project setup
55 | ```
56 | yarn install
57 | ```
58 |
59 | ### Compiles and hot-reloads for development
60 | ```
61 | yarn serve
62 | ```
63 |
64 | ### Compiles and minifies for production
65 | ```
66 | yarn build
67 | ```
68 |
69 | ### Lints and fixes files
70 | ```
71 | yarn lint
72 | ```
73 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ["@vue/cli-plugin-babel/preset"]
3 | };
4 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "shop-ts",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint --fix"
9 | },
10 | "dependencies": {
11 | "@types/qs": "^6.9.4",
12 | "axios": "^0.19.0",
13 | "better-scroll": "^1.15.2",
14 | "core-js": "^3.6.5",
15 | "qs": "^6.9.4",
16 | "register-service-worker": "^1.7.1",
17 | "swiper": "^6.1.1",
18 | "vue": "^2.6.11",
19 | "vue-class-component": "^7.2.3",
20 | "vue-property-decorator": "^8.4.2",
21 | "vue-router": "^3.2.0",
22 | "vuex": "^3.4.0",
23 | "vuex-class": "^0.3.2"
24 | },
25 | "devDependencies": {
26 | "@types/better-scroll": "^1.12.2",
27 | "@typescript-eslint/eslint-plugin": "^2.33.0",
28 | "@typescript-eslint/parser": "^2.33.0",
29 | "@vue/cli-plugin-babel": "~4.4.0",
30 | "@vue/cli-plugin-eslint": "~4.4.0",
31 | "@vue/cli-plugin-pwa": "~4.4.0",
32 | "@vue/cli-plugin-router": "~4.4.0",
33 | "@vue/cli-plugin-typescript": "~4.4.0",
34 | "@vue/cli-plugin-vuex": "~4.4.0",
35 | "@vue/cli-service": "~4.4.0",
36 | "@vue/eslint-config-prettier": "^6.0.0",
37 | "@vue/eslint-config-typescript": "^5.0.2",
38 | "compression-webpack-plugin": "^4.0.0",
39 | "eslint": "^6.7.2",
40 | "eslint-plugin-prettier": "^3.1.3",
41 | "eslint-plugin-vue": "^6.2.2",
42 | "postcss-px-to-viewport": "^1.1.1",
43 | "prettier": "^1.19.1",
44 | "sass": "^1.26.5",
45 | "sass-loader": "^8.0.2",
46 | "typescript": "~3.9.3",
47 | "vue-template-compiler": "^2.6.11"
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | plugins: {
3 | autoprefixer: {},
4 | 'postcss-px-to-viewport': {
5 | unitToConvert: 'px',
6 | viewportWidth: 750,
7 | unitPrecision: 5,
8 | propList: ['*'],
9 | viewportUnit: 'vw',
10 | fontViewportUnit: 'vw',
11 | selectorBlackList: ['lx-toast', /^.lx-load*/, /^.loading_leafy*/],
12 | minPixelValue: 1,
13 | mediaQuery: false,
14 | replace: true,
15 | exclude: [],
16 | landscape: false,
17 | landscapeUnit: 'vw',
18 | landscapeWidth: 568,
19 | },
20 | },
21 | };
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rosen97/web-shop/93dfb95e2fd232ae46363f51f69fcbe25e6fb357/public/favicon.ico
--------------------------------------------------------------------------------
/public/img/icons/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rosen97/web-shop/93dfb95e2fd232ae46363f51f69fcbe25e6fb357/public/img/icons/android-chrome-192x192.png
--------------------------------------------------------------------------------
/public/img/icons/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rosen97/web-shop/93dfb95e2fd232ae46363f51f69fcbe25e6fb357/public/img/icons/android-chrome-512x512.png
--------------------------------------------------------------------------------
/public/img/icons/android-chrome-maskable-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rosen97/web-shop/93dfb95e2fd232ae46363f51f69fcbe25e6fb357/public/img/icons/android-chrome-maskable-192x192.png
--------------------------------------------------------------------------------
/public/img/icons/android-chrome-maskable-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rosen97/web-shop/93dfb95e2fd232ae46363f51f69fcbe25e6fb357/public/img/icons/android-chrome-maskable-512x512.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rosen97/web-shop/93dfb95e2fd232ae46363f51f69fcbe25e6fb357/public/img/icons/apple-touch-icon-120x120.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rosen97/web-shop/93dfb95e2fd232ae46363f51f69fcbe25e6fb357/public/img/icons/apple-touch-icon-152x152.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rosen97/web-shop/93dfb95e2fd232ae46363f51f69fcbe25e6fb357/public/img/icons/apple-touch-icon-180x180.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rosen97/web-shop/93dfb95e2fd232ae46363f51f69fcbe25e6fb357/public/img/icons/apple-touch-icon-60x60.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rosen97/web-shop/93dfb95e2fd232ae46363f51f69fcbe25e6fb357/public/img/icons/apple-touch-icon-76x76.png
--------------------------------------------------------------------------------
/public/img/icons/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rosen97/web-shop/93dfb95e2fd232ae46363f51f69fcbe25e6fb357/public/img/icons/apple-touch-icon.png
--------------------------------------------------------------------------------
/public/img/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rosen97/web-shop/93dfb95e2fd232ae46363f51f69fcbe25e6fb357/public/img/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/public/img/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rosen97/web-shop/93dfb95e2fd232ae46363f51f69fcbe25e6fb357/public/img/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/public/img/icons/msapplication-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rosen97/web-shop/93dfb95e2fd232ae46363f51f69fcbe25e6fb357/public/img/icons/msapplication-icon-144x144.png
--------------------------------------------------------------------------------
/public/img/icons/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rosen97/web-shop/93dfb95e2fd232ae46363f51f69fcbe25e6fb357/public/img/icons/mstile-150x150.png
--------------------------------------------------------------------------------
/public/img/icons/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | <%= htmlWebpackPlugin.options.title %>
10 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
3 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
54 |
--------------------------------------------------------------------------------
/src/api/index.ts:
--------------------------------------------------------------------------------
1 | import HTTP from "../utils/http";
2 |
3 | export interface LoginParamsProps {
4 | username: string;
5 | password: string;
6 | }
7 |
8 | export interface RegisterParamsProps {
9 | username: string;
10 | password: string;
11 | email: string;
12 | phone: string;
13 | question: string;
14 | answer: string;
15 | }
16 |
17 | export interface ProductListParams {
18 | categoryId?: number;
19 | keyword?: string;
20 | pageNum: number;
21 | pageSize: number;
22 | orderBy: string;
23 | }
24 |
25 | export interface ProductDetailParams {
26 | productId: number;
27 | }
28 |
29 | /**
30 | * 检查用户登录状态
31 | */
32 | export const checkLogin = async () => HTTP.post("/user/get_user_info.do");
33 |
34 | /**
35 | * 去登录
36 | */
37 | export const userLogin = async (params: LoginParamsProps) =>
38 | HTTP.post("/user/login.do", params);
39 |
40 | /**
41 | * 注册
42 | */
43 | export const userRegister = async (params: RegisterParamsProps) =>
44 | HTTP.post("/user/register.do", params);
45 |
46 | /**
47 | * 退出登录
48 | */
49 | export const logout = async () => HTTP.post("/user/logout.do");
50 |
51 | /**
52 | * 商品列表
53 | * keyword和category不能同时传,会报错500
54 | */
55 | export const getProductList = (params: ProductListParams) =>
56 | HTTP.post("/product/list.do", params);
57 |
58 | /**
59 | * 商品详情
60 | */
61 | export const getProductDetail = (params: ProductDetailParams) =>
62 | HTTP.post("/product/detail.do", params);
63 |
--------------------------------------------------------------------------------
/src/assets/styles/index.scss:
--------------------------------------------------------------------------------
1 | @import './main.scss';
2 | @import './reset.scss';
3 | @import './mixin.scss';
--------------------------------------------------------------------------------
/src/assets/styles/main.scss:
--------------------------------------------------------------------------------
1 | body {
2 | user-select: none;
3 | }
4 |
5 | img {
6 | vertical-align: middle;
7 | }
8 |
9 | #app {
10 | width: 100%;
11 | height: 100vh;
12 | display: flex;
13 | flex-direction: column;
14 |
15 | .page-container {
16 | width: 100%;
17 | height: 100%;
18 | background-color: #f7f7f7;
19 | overflow: scroll;
20 | }
21 | }
22 |
23 | .single-omit {
24 | overflow: hidden;
25 | text-overflow: ellipsis;
26 | white-space: nowrap;
27 | }
28 |
29 | .ele-overflow-hidden {
30 | overflow: hidden !important;
31 | }
--------------------------------------------------------------------------------
/src/assets/styles/mixin.scss:
--------------------------------------------------------------------------------
1 | $orange: #FF6B01;
2 | $red: #F63515;
3 | $bc: #F7F7F7;
4 | $fc:#fff;
5 |
6 | @mixin border-top-1px($color){
7 | &:before{
8 | border-top: 1px solid $color;
9 | }
10 | }
11 | @mixin border-right-1px($color){
12 | &:before{
13 | border-right: 1px solid $color;
14 | }
15 | }
16 | @mixin border-bottom-1px($color){
17 | &:before{
18 | border-bottom: 1px solid $color;
19 | }
20 | }
21 | @mixin border-left-1px($color){
22 | &:before{
23 | border-left: 1px solid $color;
24 | }
25 | }
26 | @mixin border-1px($color){
27 | position: relative;
28 | &:after{
29 | content: '';
30 | pointer-events: none; //解决iphone上的点击无效Bug
31 | position: absolute;
32 | left: 0;
33 | top: 0;
34 | transform-origin: 0 0;
35 | border: 1px solid $color;
36 | }
37 | }
38 |
39 | //圆角
40 | @mixin borderRadius($radius) {
41 | -webkit-border-radius: $radius;
42 | -moz-border-radius: $radius;
43 | -ms-border-radius: $radius;
44 | -o-border-radius: $radius;
45 | border-radius: $radius;
46 | }
47 |
48 | //1px底部边框
49 | @mixin border-1px($color){
50 | position: relative;
51 | &:after{
52 | display: block;
53 | position: absolute;
54 | left: 0;
55 | bottom: 0;
56 | width: 100%;
57 | border-top: 1px solid $color;
58 | content: '';
59 | }
60 | }
61 | //定位全屏
62 | @mixin allcover{
63 | position:absolute;
64 | top:0;
65 | right:0;
66 | }
67 |
68 | //定位上下左右居中
69 | @mixin center {
70 | position: absolute;
71 | top: 50%;
72 | left: 50%;
73 | transform: translate(-50%, -50%);
74 | }
75 |
76 | //定位上下居中
77 | @mixin ct {
78 | position: absolute;
79 | top: 50%;
80 | transform: translateY(-50%);
81 | }
82 |
83 | //定位左右居中
84 | @mixin cl {
85 | position: absolute;
86 | left: 50%;
87 | transform: translateX(-50%);
88 | }
89 |
90 | //宽高
91 | @mixin wh($width, $height){
92 | width: $width;
93 | height: $height;
94 | }
95 |
96 | //字体大小、行高、字体
97 | @mixin font($size, $line-height, $family: 'Microsoft YaHei') {
98 | font: #{$size}/#{$line-height} $family;
99 | }
100 |
101 | //字体大小,颜色
102 | @mixin sc($size, $color){
103 | font-size: $size;
104 | color: $color;
105 | }
106 |
107 | @mixin boxSizing{
108 | -webkit-box-sizing: border-box;
109 | -moz-box-sizing: border-box;
110 | box-sizing: border-box;
111 | }
112 |
113 | //flex 布局和 子元素 对其方式
114 | @mixin fj($type: space-between){
115 | display: flex;
116 | justify-content: $type;
117 | }
118 |
--------------------------------------------------------------------------------
/src/assets/styles/reset.scss:
--------------------------------------------------------------------------------
1 | /* http://meyerweb.com/eric/tools/css/reset/
2 | v2.0 | 20110126
3 | License: none (public domain)
4 | */
5 |
6 | html,
7 | body,
8 | div,
9 | span,
10 | applet,
11 | object,
12 | iframe,
13 | h1,
14 | h2,
15 | h3,
16 | h4,
17 | h5,
18 | h6,
19 | p,
20 | blockquote,
21 | pre,
22 | a,
23 | abbr,
24 | acronym,
25 | address,
26 | big,
27 | cite,
28 | code,
29 | del,
30 | dfn,
31 | em,
32 | img,
33 | ins,
34 | kbd,
35 | q,
36 | s,
37 | samp,
38 | small,
39 | strike,
40 | strong,
41 | sub,
42 | sup,
43 | tt,
44 | var,
45 | b,
46 | u,
47 | i,
48 | center,
49 | dl,
50 | dt,
51 | dd,
52 | ol,
53 | ul,
54 | li,
55 | fieldset,
56 | form,
57 | label,
58 | legend,
59 | table,
60 | caption,
61 | tbody,
62 | tfoot,
63 | thead,
64 | tr,
65 | th,
66 | td,
67 | article,
68 | aside,
69 | canvas,
70 | details,
71 | embed,
72 | figure,
73 | figcaption,
74 | footer,
75 | header,
76 | hgroup,
77 | menu,
78 | nav,
79 | output,
80 | ruby,
81 | section,
82 | summary,
83 | time,
84 | mark,
85 | audio,
86 | video {
87 | margin: 0;
88 | padding: 0;
89 | border: 0;
90 | font-size: 100%;
91 | font: inherit;
92 | vertical-align: baseline;
93 | }
94 |
95 | /* HTML5 display-role reset for older browsers */
96 | article,
97 | aside,
98 | details,
99 | figcaption,
100 | figure,
101 | footer,
102 | header,
103 | hgroup,
104 | menu,
105 | nav,
106 | section {
107 | display: block;
108 | }
109 |
110 | body {
111 | line-height: 1;
112 | }
113 |
114 | ol,
115 | ul {
116 | list-style: none;
117 | }
118 |
119 | blockquote,
120 | q {
121 | quotes: none;
122 | }
123 |
124 | blockquote:before,
125 | blockquote:after,
126 | q:before,
127 | q:after {
128 | content: '';
129 | content: none;
130 | }
131 |
132 | table {
133 | border-collapse: collapse;
134 | border-spacing: 0;
135 | }
136 |
137 | input {
138 | border: none;
139 | outline: none;
140 | -webkit-appearance: none;
141 | -webkit-appearance: none;
142 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
143 | }
144 |
145 | textarea {
146 | border: none;
147 | outline: none;
148 | }
149 |
150 | button {
151 | border: none;
152 | outline: none;
153 | }
154 |
155 | a {
156 | text-decoration: none;
157 | color: #333;
158 | }
159 |
160 | li {
161 | list-style-type: none;
162 | }
--------------------------------------------------------------------------------
/src/components/confirm/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
{{title}}
6 |
7 | 取消
8 | 确定
9 |
10 |
11 |
12 |
13 |
14 |
27 |
28 |
--------------------------------------------------------------------------------
/src/components/menu/index.scss:
--------------------------------------------------------------------------------
1 | .nav-bar {
2 | width: 100%;
3 | padding: 10px 0;
4 | z-index: 10;
5 | background: #fff;
6 | transform: translateZ(0);
7 | -webkit-transform: translateZ(0);
8 |
9 | .nav-list {
10 | width: 100%;
11 | @include fj;
12 | flex-direction: row;
13 | padding: 0;
14 |
15 | .nav-list-item {
16 | display: flex;
17 | flex: 1;
18 | flex-direction: column;
19 | text-align: center;
20 | color: #666;
21 |
22 | &.active {
23 | color: $red;
24 | }
25 |
26 | i {
27 | text-align: center;
28 | font-size: 44px;
29 | }
30 |
31 | span {
32 | font-size: 24px;
33 | }
34 | }
35 | }
36 | }
--------------------------------------------------------------------------------
/src/components/menu/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | -
11 |
12 | {{item.name}}
13 |
14 |
15 |
16 |
17 |
61 |
62 |
--------------------------------------------------------------------------------
/src/components/modal/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | modal
4 |
5 |
6 |
7 |
13 |
14 |
25 |
--------------------------------------------------------------------------------
/src/components/page-head/assets/index.scss:
--------------------------------------------------------------------------------
1 | .page-header {
2 | width: 100%;
3 | height: 88px;
4 | padding: 0 20px;
5 | display: flex;
6 | justify-content: space-between;
7 | align-items: center;
8 | box-sizing: border-box;
9 | background-color: #fff;
10 |
11 | &.white {
12 | background: $red;
13 | }
14 |
15 | .left img {
16 | display: block;
17 | width: 40px;
18 | height: 40px;
19 | border: none;
20 | }
21 |
22 | .title {
23 | font-size: 36px;
24 | color: #272727;
25 |
26 | &.white {
27 | color: #fff;
28 | }
29 | }
30 | }
--------------------------------------------------------------------------------
/src/components/page-head/assets/left-normal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rosen97/web-shop/93dfb95e2fd232ae46363f51f69fcbe25e6fb357/src/components/page-head/assets/left-normal.png
--------------------------------------------------------------------------------
/src/components/page-head/assets/left-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rosen97/web-shop/93dfb95e2fd232ae46363f51f69fcbe25e6fb357/src/components/page-head/assets/left-white.png
--------------------------------------------------------------------------------
/src/components/page-head/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
30 |
31 |
--------------------------------------------------------------------------------
/src/components/product-item/index.scss:
--------------------------------------------------------------------------------
1 | .product-item {
2 | @include fj;
3 | width: 100%;
4 | height: 240px;
5 | padding: 20px 0;
6 | border-bottom: 1px solid #dcdcdc;
7 |
8 | img {
9 | width: 280px;
10 | height: 240px;
11 | padding: 0 20px;
12 | @include boxSizing;
13 | }
14 |
15 | .product-info {
16 | width: 56%;
17 | height: 240px;
18 | padding: 10px;
19 | @include boxSizing;
20 |
21 | .name {
22 | width: 100%;
23 | max-height: 80px;
24 | line-height: 40px;
25 | font-size: 30px;
26 | color: #333;
27 | overflow: hidden;
28 | }
29 |
30 | .subtitle {
31 | width: 100%;
32 | max-height: 40px;
33 | padding: 20px 0;
34 | line-height: 50px;
35 | font-size: 26px;
36 | color: #999;
37 | overflow: hidden;
38 | }
39 |
40 | .price {
41 | color: $red;
42 | font-size: 32px;
43 | }
44 | }
45 | }
--------------------------------------------------------------------------------
/src/components/product-item/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
![]()
4 |

5 |
6 |
{{info.name}}
7 |
{{info.subtitle}}
8 |
¥ {{info.price}}
9 |
10 |
11 |
12 |
13 |
27 |
28 |
--------------------------------------------------------------------------------
/src/components/product-item/product_default.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rosen97/web-shop/93dfb95e2fd232ae46363f51f69fcbe25e6fb357/src/components/product-item/product_default.jpg
--------------------------------------------------------------------------------
/src/components/scroll/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 |
45 |
46 |
--------------------------------------------------------------------------------
/src/config/index.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rosen97/web-shop/93dfb95e2fd232ae46363f51f69fcbe25e6fb357/src/config/index.ts
--------------------------------------------------------------------------------
/src/main.ts:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import App from "./App.vue";
3 | import "./registerServiceWorker";
4 | import router from "./router";
5 | import store from "./store";
6 | import "./assets/styles/index.scss";
7 |
8 | Vue.config.productionTip = false;
9 |
10 | new Vue({
11 | router,
12 | store,
13 | render: (h) => h(App),
14 | }).$mount("#app");
15 |
--------------------------------------------------------------------------------
/src/mock/data.ts:
--------------------------------------------------------------------------------
1 | export interface DataProps {
2 | headList: Array;
3 | categoryList: Array;
4 | floorList: Array
5 | }
6 | export const homeData = {
7 | headList: [
8 | {
9 | imgUrl:
10 | "//m.360buyimg.com/mobilecms/s1125x690_jfs/t29188/301/133996293/200131/61f42a01/5be8eed6Nda6a18a5.jpg!cr_1125x549_0_72!q70.jpg.dpg",
11 | categoryId: 100008,
12 | },
13 | {
14 | imgUrl:
15 | "//m.360buyimg.com/mobilecms/s1125x690_jfs/t30757/316/208746402/123953/9fa18794/5beb7d13Ne77e9f29.jpg!cr_1125x549_0_72!q70.jpg.dpg",
16 | categoryId: 100016,
17 | },
18 | {
19 | imgUrl:
20 | "//m.360buyimg.com/mobilecms/jfs/t1/3926/29/4138/254748/5b9b646dE45cbeb7f/f80c8f7c24273bc1.jpg!cr_1125x549_0_72",
21 | categoryId: 100035,
22 | },
23 | ],
24 | categoryList: [
25 | {
26 | name: "M超市",
27 | imgUrl:
28 | "//m.360buyimg.com/mobilecms/jfs/t25534/207/1767774998/8085/523157d6/5bbc800fN502129b8.png",
29 | categoryId: 100002,
30 | },
31 | {
32 | name: "全球购",
33 | imgUrl:
34 | "//m.360buyimg.com/mobilecms/jfs/t21658/347/221358098/7461/f86e6f74/5b03b170Nc9e0ec7c.png",
35 | categoryId: 100002,
36 | },
37 | {
38 | name: "M时尚",
39 | imgUrl:
40 | "//m.360buyimg.com/mobilecms/jfs/t1/8385/17/3537/17895/5bd6ca67E09d23550/32d965fe9a9087a2.png",
41 | categoryId: 100002,
42 | },
43 | {
44 | name: "M生鲜",
45 | imgUrl:
46 | "//m.360buyimg.com/mobilecms/jfs/t17725/156/1767366877/17404/f45d418b/5ad87bf0N66c5db7c.png",
47 | categoryId: 100002,
48 | },
49 | {
50 | name: "M到家",
51 | imgUrl:
52 | "//m.360buyimg.com/mobilecms/jfs/t16990/157/2001547525/17770/a7b93378/5ae01befN2494769f.png",
53 | categoryId: 100002,
54 | },
55 | {
56 | name: "充值缴费",
57 | imgUrl:
58 | "//m.360buyimg.com/mobilecms/jfs/t18454/342/2607665324/6406/273daced/5b03b74eN3541598d.png",
59 | categoryId: 100002,
60 | },
61 | {
62 | name: "9.9元拼",
63 | imgUrl:
64 | "//m.360buyimg.com/mobilecms/jfs/t22228/270/207441984/11564/88140ab7/5b03fae3N67f78fe3.png",
65 | categoryId: 100002,
66 | },
67 | {
68 | name: "领劵",
69 | imgUrl:
70 | "//m.360buyimg.com/mobilecms/jfs/t25258/200/2527038521/14019/3d7a8470/5be92494N557a0c5b.png",
71 | categoryId: 100002,
72 | },
73 | {
74 | name: "省钱",
75 | imgUrl:
76 | "//m.360buyimg.com/mobilecms/jfs/t22120/183/200496447/5553/91ed22e0/5b03b7b8Ncea08c5b.png",
77 | categoryId: 100002,
78 | },
79 | {
80 | name: "全部",
81 | imgUrl:
82 | "//m.360buyimg.com/mobilecms/jfs/t21481/263/412160889/15938/4246b4f8/5b0cea29N8fb2865f.png",
83 | categoryId: 100002,
84 | },
85 | ],
86 | floorList: [
87 | {
88 | headUrl:
89 | "//m.360buyimg.com/mobilecms/jfs/t15526/56/2344102455/23273/d8e15d5a/5aa0dbc1Nefd2bd2a.png!q70.jpg.dpg",
90 | list: [
91 | {
92 | title: "玩3C",
93 | desc: "黑鲨新品大爆炸",
94 | products: [
95 | {
96 | imgUrl:
97 | "//m.360buyimg.com/n1/jfs/t25144/2/1278469398/101844/cb66b21/5b90f5bfNcd58f18b.png!q70.jpg.dpg",
98 | categoryId: 100001,
99 | },
100 | {
101 | imgUrl:
102 | "//m.360buyimg.com/mobilecms/s240x240_jfs/t22792/274/2587775944/59292/3666f607/5b87bf15N9409ba0e.png!q70.jpg.dpg",
103 | categoryId: 100002,
104 | },
105 | ],
106 | },
107 | {
108 | title: "MMall家电",
109 | desc: "家电狂欢 京彩有你",
110 | products: [
111 | {
112 | imgUrl:
113 | "//m.360buyimg.com/mobilecms/s240x240_jfs/t22363/318/1484948466/11138/8317fc9b/5b2a528eN7c6bde83.jpg!q70.jpg.dpg",
114 | categoryId: 100003,
115 | },
116 | {
117 | imgUrl:
118 | "//m.360buyimg.com/mobilecms/s240x240_jfs/t22666/293/257815171/29274/6b5605b1/5b2a5295N5a81ad96.jpg!q70.jpg.dpg",
119 | categoryId: 100004,
120 | },
121 | ],
122 | },
123 | {
124 | title: "MMall超市",
125 | desc: "超市大放价 抢超值好货",
126 | products: [
127 | {
128 | imgUrl:
129 | "//m.360buyimg.com/n1/jfs/t16852/170/2693122660/56143/28da8c2a/5b063c63N5746e4e4.jpg!q70.jpg.dpg",
130 | categoryId: 100005,
131 | },
132 | {
133 | imgUrl:
134 | "//m.360buyimg.com/n1/jfs/t18877/293/2631103430/85245/f220b40d/5b063c6fN7820b399.jpg!q70.jpg.dpg",
135 | categoryId: 100006,
136 | },
137 | ],
138 | },
139 | {
140 | title: "爱家",
141 | desc: "家纺热卖 部分低至9.9元",
142 | products: [
143 | {
144 | imgUrl:
145 | "//m.360buyimg.com/mobilecms/s240x240_jfs/t15244/283/356547262/47743/b6607b0f/5a2a6d51N8830e8b8.jpg!q70.jpg.dpg",
146 | categoryId: 100007,
147 | },
148 | {
149 | imgUrl:
150 | "//m.360buyimg.com/mobilecms/s240x240_jfs/t16057/38/102057973/36179/b957e4ec/5a2a6d55N83655f7f.jpg!q70.jpg.dpg",
151 | categoryId: 100008,
152 | },
153 | ],
154 | },
155 | {
156 | title: "家有萌宝",
157 | desc: "低至五折",
158 | products: [
159 | {
160 | imgUrl:
161 | "//m.360buyimg.com/n1/jfs/t17929/299/899794385/17291/d90318f9/5ab4c680N7d291625.jpg!q70.jpg.dpg",
162 | categoryId: 100009,
163 | },
164 | {
165 | imgUrl:
166 | "//m.360buyimg.com/n1/jfs/t18802/262/2452746578/333259/5dcdfb06/5af3ffb4N0c700b57.jpg!q70.jpg.dpg",
167 | categoryId: 100010,
168 | },
169 | ],
170 | },
171 | {
172 | title: "爱吃",
173 | desc: "9.9包邮,夏日也生动",
174 | products: [
175 | {
176 | imgUrl:
177 | "//m.360buyimg.com/mobilecms/s240x240_jfs/t14473/103/2042876100/41836/766c1953/5a697f47Nc952ed7f.jpg!q70.jpg.dpg",
178 | categoryId: 100011,
179 | },
180 | {
181 | imgUrl:
182 | "//m.360buyimg.com/mobilecms/s240x240_jfs/t17155/227/2678303408/52223/f7a950c/5b0535d6Ne4073be7.jpg!q70.jpg.dpg",
183 | categoryId: 100012,
184 | },
185 | ],
186 | },
187 | ],
188 | },
189 | {
190 | headUrl:
191 | "//m.360buyimg.com/mobilecms/jfs/t19381/275/717008577/26686/e58b7ef4/5aa23f27Nfa6d6be3.png!q70.jpg.dpg",
192 | list: [
193 | {
194 | title: "智能家电馆",
195 | desc: "满减狂欢",
196 | products: [
197 | {
198 | imgUrl:
199 | "//m.360buyimg.com/mobilecms/s240x240_jfs/t25183/247/391394027/33684/8e1af9dc/5b6d048aNd7dae520.jpg!q70.jpg.dpg",
200 | categoryId: 100013,
201 | },
202 | {
203 | imgUrl:
204 | "//m.360buyimg.com/mobilecms/s240x240_jfs/t1/839/25/11121/19615/5bccb3a0E4b504f77/e55c2fb826efe911.jpg!q70.jpg.dpg",
205 | categoryId: 100014,
206 | },
207 | ],
208 | },
209 | {
210 | title: "珠宝馆",
211 | desc: "满减优惠",
212 | products: [
213 | {
214 | imgUrl:
215 | "//m.360buyimg.com/n1/jfs/t19009/357/347377157/13661/d0d9e5fb/5a6e8bb3Nd6182f9f.jpg!q70.jpg.dpg",
216 | categoryId: 100015,
217 | },
218 | {
219 | imgUrl:
220 | "//m.360buyimg.com/n1/jfs/t27889/231/477152414/149859/7a5fb585/5baf1f58N45c2ca6c.jpg!q70.jpg.dpg",
221 | categoryId: 100016,
222 | },
223 | ],
224 | },
225 | {
226 | title: "鞋靴箱包",
227 | desc: "低至五折",
228 | products: [
229 | {
230 | imgUrl:
231 | "//m.360buyimg.com/n1/jfs/t21469/359/769885083/29352/68865ed/5b178e49Nc5db7341.jpg!q70.jpg.dpg",
232 | categoryId: 100017,
233 | },
234 | {
235 | imgUrl:
236 | "//m.360buyimg.com/mobilecms/jfs/t1/7091/11/2919/441267/5bd578bfE03e7166a/c5d5222c1802fd21.jpg!q70.jpg.dpg",
237 | categoryId: 100018,
238 | },
239 | ],
240 | },
241 | {
242 | title: "童装馆",
243 | desc: "春夏小萌娃",
244 | products: [
245 | {
246 | imgUrl:
247 | "//m.360buyimg.com/n1/jfs/t20614/194/808562651/89118/894d41a5/5b18ba8dN855ebe44.png!q70.jpg.dpg",
248 | categoryId: 100019,
249 | },
250 | {
251 | imgUrl:
252 | "//m.360buyimg.com/n1/jfs/t12460/183/2350810548/47292/f4c5485/5a914202Nfc1b8a12.png!q70.jpg.dpg",
253 | categoryId: 100020,
254 | },
255 | ],
256 | },
257 | ],
258 | },
259 | ],
260 | };
261 | export const categoryData = [
262 | {
263 | name: "手机数码",
264 | mainImgUrl:
265 | "//img20.360buyimg.com/mcoss/jfs/t16273/143/46476745/45673/cba0840c/5a28ef10N82ab81d3.jpg",
266 | list: [
267 | {
268 | title: "手机通讯",
269 | productList: [
270 | {
271 | title: "手机",
272 | imgUrl:
273 | "//img10.360buyimg.com/focus/s140x140_jfs/t11503/241/2246064496/4783/cea2850e/5a169216N0701c7f1.jpg",
274 | },
275 | {
276 | title: "全面屏手机",
277 | imgUrl:
278 | "//img30.360buyimg.com/focus/s140x140_jfs/t18955/187/1309277884/11517/fe100782/5ac48d27N3f5bb821.jpg",
279 | },
280 | {
281 | title: "游戏手机",
282 | imgUrl:
283 | "//img11.360buyimg.com/focus/s140x140_jfs/t11470/45/2362968077/2689/fb36d9a0/5a169238Nc8f0882b.jpg",
284 | },
285 | {
286 | title: "拍照手机",
287 | imgUrl:
288 | "//img20.360buyimg.com/focus/s140x140_jfs/t12022/66/917351804/2257/7ddc58e5/5a169232Ndf76f53c.jpg",
289 | },
290 | {
291 | title: "老年机",
292 | imgUrl:
293 | "//img12.360buyimg.com/focus/s140x140_jfs/t11461/339/2354953633/8254/8c8c50d3/5a169217N5d1b842e.jpg",
294 | },
295 | {
296 | title: "女性手机",
297 | imgUrl:
298 | "//img12.360buyimg.com/focus/s140x140_jfs/t15790/6/2311892256/2742/5ed77924/5a9fa728Nbff29ad2.jpg",
299 | },
300 | ],
301 | },
302 | {
303 | title: "手机配件",
304 | productList: [
305 | {
306 | title: "数据线",
307 | imgUrl:
308 | "//img12.360buyimg.com/focus/s140x140_jfs/t18055/312/1342501458/9462/4699ed8a/5ac48672N11cf61fe.jpg",
309 | },
310 | {
311 | title: "手机壳",
312 | imgUrl:
313 | "//img30.360buyimg.com/focus/s140x140_jfs/t18502/160/1284774717/9251/feb8a496/5ac4878cN658cbb07.jpg",
314 | },
315 | {
316 | title: "充电宝",
317 | imgUrl:
318 | "//img30.360buyimg.com/focus/s140x140_jfs/t19537/23/1276961949/9676/f4b5be0d/5ac48791Nb224f939.jpg",
319 | },
320 | {
321 | title: "手机贴膜",
322 | imgUrl:
323 | "//img11.360buyimg.com/focus/s140x140_jfs/t17548/288/1331085893/6458/52545456/5ac486c6N0c8a93dc.jpg",
324 | },
325 | {
326 | title: "耳机",
327 | imgUrl:
328 | "//img10.360buyimg.com/focus/s140x140_jfs/t17284/353/1280266808/3696/32c00915/5ac486ccN2d8031c1.jpg",
329 | },
330 | {
331 | title: "充电器",
332 | imgUrl:
333 | "//img11.360buyimg.com/focus/s140x140_jfs/t16774/124/1318736793/3884/cb658723/5ac4874fN6bc007b0.jpg",
334 | },
335 | ],
336 | },
337 | {
338 | title: "摄影摄像",
339 | productList: [
340 | {
341 | title: "单反相机",
342 | imgUrl:
343 | "//img14.360buyimg.com/focus/s140x140_jfs/t13765/295/926307178/7966/3228af24/5a1679f2Nc2f659b6.jpg",
344 | },
345 | {
346 | title: "数码相机",
347 | imgUrl:
348 | "//img20.360buyimg.com/focus/s140x140_jfs/t12814/251/897168610/8107/60a873f/5a1679caNada7f827.jpg",
349 | },
350 | {
351 | title: "镜头",
352 | imgUrl:
353 | "//img30.360buyimg.com/focus/s140x140_jfs/t12154/164/880046972/2880/86b45b51/5a1679b9N42a5f8e5.jpg",
354 | },
355 | {
356 | title: "户外器材",
357 | imgUrl:
358 | "//img10.360buyimg.com/focus/s140x140_jfs/t12586/176/939117172/2550/d16b4b6c/5a1679c3N67e2b3f1.jpg",
359 | },
360 | ],
361 | },
362 | ],
363 | },
364 | {
365 | name: "电脑办公",
366 | mainImgUrl:
367 | "//img30.360buyimg.com/mcoss/jfs/t14743/292/279117506/48503/9b7d9f2c/5a28ea97N36cb4d16.jpg",
368 | list: [
369 | {
370 | title: "热门分类",
371 | productList: [
372 | {
373 | title: "轻薄本",
374 | imgUrl:
375 | "//img13.360buyimg.com/focus/s140x140_jfs/t11071/195/2462134264/9117/cd0688bf/5a17ba79N18b9f3d4.png",
376 | },
377 | {
378 | title: "游戏本",
379 | imgUrl:
380 | "//img30.360buyimg.com/focus/s140x140_jfs/t11155/36/2330310765/10690/eb6754c3/5a17ba96N49561fea.png",
381 | },
382 | {
383 | title: "机械键盘",
384 | imgUrl:
385 | "//img12.360buyimg.com/focus/s140x140_jfs/t12304/245/965858782/6481/37cb5a9b/5a17ba5aN0406a1b5.jpg",
386 | },
387 | {
388 | title: "组装电脑",
389 | imgUrl:
390 | "//img10.360buyimg.com/focus/s140x140_jfs/t14101/325/978287093/8836/e142aa53/5a17ba73N07b12f0c.jpg",
391 | },
392 | {
393 | title: "移动硬盘",
394 | imgUrl:
395 | "//img12.360buyimg.com/focus/s140x140_jfs/t13228/333/989759736/4764/2a312c2e/5a17ba7fN0740c051.jpg",
396 | },
397 | {
398 | title: "曲屏显示器",
399 | imgUrl:
400 | "//img30.360buyimg.com/focus/s140x140_jfs/t13798/322/988648789/3644/1adc5615/5a17ba6dNafc95373.jpg",
401 | },
402 | ],
403 | },
404 | {
405 | title: "外设产品",
406 | productList: [
407 | {
408 | title: "鼠标",
409 | imgUrl:
410 | "//img20.360buyimg.com/focus/s140x140_jfs/t11881/31/2355374158/3676/22da94de/5a16a5f0Nc6b32dda.jpg",
411 | },
412 | {
413 | title: "U盘",
414 | imgUrl:
415 | "//img20.360buyimg.com/focus/s140x140_jfs/t12112/355/904591745/4308/6201dffe/5a16a5aaNdac2fe89.jpg",
416 | },
417 | {
418 | title: "插座",
419 | imgUrl:
420 | "//img14.360buyimg.com/focus/s140x140_jfs/t12031/206/932335399/3567/d6d59ad9/5a16a578N283a0f75.jpg",
421 | },
422 | {
423 | title: "电脑工具",
424 | imgUrl:
425 | "//img11.360buyimg.com/focus/s140x140_jfs/t12292/173/915309013/5554/78f4ab5e/5a16a560Nc7626d33.jpg",
426 | },
427 | {
428 | title: "摄像头",
429 | imgUrl:
430 | "//img20.360buyimg.com/focus/s140x140_jfs/t12499/54/910206832/5998/f91002f8/5a16a588Nff477d9d.jpg",
431 | },
432 | {
433 | title: "手写板",
434 | imgUrl:
435 | "//img13.360buyimg.com/focus/s140x140_jfs/t11734/189/2377033150/4145/b78bfcf/5a16a594Ncb41c95a.jpg",
436 | },
437 | ],
438 | },
439 | ],
440 | },
441 | {
442 | name: "家用电器",
443 | mainImgUrl: "",
444 | list: [
445 | {
446 | title: "家用电器",
447 | productList: [
448 | {
449 | title: "电饭煲",
450 | imgUrl:
451 | "//img11.360buyimg.com/focus/s140x140_jfs/t14185/134/950962305/3800/eb1bafb8/5a17f224Nea1d3f59.jpg",
452 | },
453 | {
454 | title: "豆浆机",
455 | imgUrl:
456 | "//img11.360buyimg.com/focus/s140x140_jfs/t14065/132/988058896/1688/99cd0a3d/5a17f229Nc4c681fb.jpg",
457 | },
458 | {
459 | title: "冰箱",
460 | imgUrl:
461 | "//img12.360buyimg.com/focus/s140x140_jfs/t13153/44/964603695/1011/21d660d2/5a17f6aeN280056ea.jpg",
462 | },
463 | {
464 | title: "双开门冰箱",
465 | imgUrl:
466 | "//img20.360buyimg.com/focus/s140x140_jfs/t13588/266/943842715/1088/c4ae40e4/5a17f6c5Ne56d7e26.jpg",
467 | },
468 | {
469 | title: "冷柜",
470 | imgUrl:
471 | "//img12.360buyimg.com/focus/s140x140_jfs/t12928/273/1007467483/3549/52dad666/5a17f69eN1d10e257.jpg",
472 | },
473 | {
474 | title: "洗衣机",
475 | imgUrl:
476 | "//img12.360buyimg.com/focus/s140x140_jfs/t12481/129/1018625238/1840/43d49869/5a17f6eaN9ec936de.jpg",
477 | },
478 | {
479 | title: "电热水器",
480 | imgUrl:
481 | "//img13.360buyimg.com/focus/s140x140_jfs/t11053/246/2459202669/4318/fd6bd8d1/5a17f356Nd692ab74.jpg",
482 | },
483 | {
484 | title: "电视",
485 | imgUrl:
486 | "//img12.360buyimg.com/focus/s140x140_jfs/t11842/356/2416901099/2164/ab77fbaa/5a17f71eN25360979.jpg",
487 | },
488 | {
489 | title: "4K超清电视",
490 | imgUrl:
491 | "//img30.360buyimg.com/focus/s140x140_jfs/t11386/179/2470866031/2353/dfc7d933/5a17f72cN97075084.jpg",
492 | },
493 | ],
494 | },
495 | ],
496 | },
497 | {
498 | name: "美妆护肤",
499 | mainImgUrl: "",
500 | list: [
501 | {
502 | title: "美妆护肤",
503 | productList: [
504 | {
505 | title: "美白",
506 | imgUrl:
507 | "//img30.360buyimg.com/focus/s140x140_jfs/t19531/110/2538137867/14848/c3ec84ac/5afd3cc5N8aa4b7c8.jpg",
508 | },
509 | {
510 | title: "防晒",
511 | imgUrl:
512 | "//img30.360buyimg.com/focus/s140x140_jfs/t17560/320/2504739891/10347/f04150c4/5afd3cbeN77d00886.jpg",
513 | },
514 | {
515 | title: "控油",
516 | imgUrl:
517 | "//img14.360buyimg.com/focus/s140x140_jfs/t19291/98/2577005836/12222/7107fb29/5afd3cc9N3add85ae.jpg",
518 | },
519 | ],
520 | },
521 | ],
522 | },
523 | {
524 | name: "男装男鞋",
525 | mainImgUrl: "",
526 | list: [
527 | {
528 | title: "男装男鞋",
529 | productList: [
530 | {
531 | title: "夹克",
532 | imgUrl:
533 | "//img13.360buyimg.com/focus/s140x140_jfs/t12514/85/571462957/6214/29cdf637/5a0e9496Necd5bd0e.jpg",
534 | },
535 | {
536 | title: "风衣",
537 | imgUrl:
538 | "//img11.360buyimg.com/focus/s140x140_jfs/t11590/82/2013872051/5874/83b5772d/5a0e947eN67f0e537.jpg",
539 | },
540 | {
541 | title: "西服",
542 | imgUrl:
543 | "//img13.360buyimg.com/focus/s140x140_jfs/t13489/68/552491077/2495/7b517e4b/5a0e9483Na6231535.jpg",
544 | },
545 | ],
546 | },
547 | ],
548 | },
549 | {
550 | name: "女装女鞋",
551 | mainImgUrl: "",
552 | list: [
553 | {
554 | title: "家用电器",
555 | productList: [
556 | {
557 | title: "风衣",
558 | imgUrl:
559 | "//img12.360buyimg.com/focus/s140x140_jfs/t15313/145/2476673176/2856/879136d7/5a9fc012N86f3fb22.jpg",
560 | },
561 | {
562 | title: "长袖T恤",
563 | imgUrl:
564 | "//img13.360buyimg.com/focus/s140x140_jfs/t16750/238/698160610/5156/5b1f25b/5a9fbfccN574cba12.jpg",
565 | },
566 | {
567 | title: "卫衣",
568 | imgUrl:
569 | "//img30.360buyimg.com/focus/s140x140_jfs/t11953/286/2195921828/5728/75b86d5b/5a127fbaN2780918c.jpg",
570 | },
571 | ],
572 | },
573 | ],
574 | },
575 | {
576 | name: "母婴童装",
577 | mainImgUrl: "",
578 | list: [
579 | {
580 | title: "母婴童装",
581 | productList: [
582 | {
583 | title: "套装",
584 | imgUrl:
585 | "//img14.360buyimg.com/focus/s140x140_jfs/t18790/111/673564180/2396/3d27d79a/5a9f94c1N5b0c8724.jpg",
586 | },
587 | ],
588 | },
589 | ],
590 | },
591 | {
592 | name: "图书音像",
593 | mainImgUrl: "",
594 | list: [
595 | {
596 | title: "图书音像",
597 | productList: [
598 | {
599 | title: "文学",
600 | imgUrl:
601 | "//img12.360buyimg.com/focus/s140x140_jfs/t19882/234/705045012/17917/e840651a/5b07dfddN7d635871.jpg",
602 | },
603 | {
604 | title: "童书",
605 | imgUrl:
606 | "//img30.360buyimg.com/focus/s140x140_jfs/t18520/109/1790543750/23751/a98be11f/5ad82a1cN400c11d1.jpg",
607 | },
608 | ],
609 | },
610 | ],
611 | },
612 | {
613 | name: "户外运动",
614 | mainImgUrl: "",
615 | list: [
616 | {
617 | title: "户外运动",
618 | productList: [
619 | {
620 | title: "跑步鞋",
621 | imgUrl:
622 | "//img30.360buyimg.com/focus/s140x140_jfs/t13993/246/156269250/8757/12386c/5a1fb5e7N12a676b6.jpg",
623 | },
624 | {
625 | title: "体育用品",
626 | imgUrl:
627 | "//img13.360buyimg.com/focus/s140x140_jfs/t12313/239/1414060687/10293/ca8ad748/5a1fb5e1Nd80abbc2.jpg",
628 | },
629 | ],
630 | },
631 | ],
632 | },
633 | {
634 | name: "食品生鲜",
635 | mainImgUrl: "",
636 | list: [
637 | {
638 | title: "家用电器",
639 | productList: [
640 | {
641 | title: "休闲零食",
642 | imgUrl:
643 | "//img10.360buyimg.com/focus/s140x140_jfs/t19789/191/2614150696/17735/d2db9aca/5b02411eNb44a03f7.jpg",
644 | },
645 | {
646 | title: "牛奶",
647 | imgUrl:
648 | "//img13.360buyimg.com/focus/s140x140_jfs/t17479/1/2588472716/22795/d676e57a/5b024117N06151eba.jpg",
649 | },
650 | ],
651 | },
652 | ],
653 | },
654 | {
655 | name: "酒水饮料",
656 | mainImgUrl: "",
657 | list: [
658 | {
659 | title: "酒水饮料",
660 | productList: [
661 | {
662 | title: "酒品馆",
663 | imgUrl:
664 | "//img14.360buyimg.com/focus/s140x140_jfs/t19432/178/2607825443/22589/446a22a2/5b023705N12de0824.jpg",
665 | },
666 | ],
667 | },
668 | ],
669 | },
670 | {
671 | name: "家居家装",
672 | mainImgUrl: "",
673 | list: [
674 | {
675 | title: "家居家装",
676 | productList: [
677 | {
678 | title: "实木餐桌",
679 | imgUrl:
680 | "//img13.360buyimg.com/focus/s140x140_jfs/t12772/3/1793374412/9705/e633967a/5a28e6c9N8aaaea3f.jpg",
681 | },
682 | {
683 | title: "椅子",
684 | imgUrl:
685 | "//img10.360buyimg.com/focus/s140x140_jfs/t13888/280/1737354934/3036/f94ecdf8/5a28e0d6N80f30096.jpg",
686 | },
687 | ],
688 | },
689 | ],
690 | },
691 | {
692 | name: "箱包手袋",
693 | mainImgUrl: "",
694 | list: [
695 | {
696 | title: "箱包手袋",
697 | productList: [
698 | {
699 | title: "箱子",
700 | imgUrl:
701 | "//img20.360buyimg.com/focus/s140x140_jfs/t12364/153/835832532/6803/5b58b137/5a152fb3Nb9f571ea.jpg",
702 | },
703 | ],
704 | },
705 | ],
706 | },
707 | {
708 | name: "钟表珠宝",
709 | mainImgUrl: "",
710 | list: [
711 | {
712 | title: "钟表珠宝",
713 | productList: [
714 | {
715 | title: "瑞士手表",
716 | imgUrl:
717 | "//img10.360buyimg.com/focus/s140x140_jfs/t14155/271/890296038/3841/f1adee7f/5a166fe1Nc6bd2f12.jpg",
718 | },
719 | ],
720 | },
721 | ],
722 | },
723 | {
724 | name: "玩具乐器",
725 | mainImgUrl: "",
726 | list: [
727 | {
728 | title: "家用电器",
729 | productList: [
730 | {
731 | title: "遥控车",
732 | imgUrl:
733 | "//img12.360buyimg.com/focus/s140x140_jfs/t17575/123/2617650159/16720/74c14629/5b02a0c6N3f2770d9.jpg",
734 | },
735 | ],
736 | },
737 | ],
738 | },
739 | ];
740 | export const hotData = [
741 | {
742 | title: "小米手机",
743 | hot: 1,
744 | },
745 | {
746 | title: "笔记本",
747 | hot: 1,
748 | },
749 | {
750 | title: "电脑",
751 | hot: 0,
752 | },
753 | {
754 | title: "平板",
755 | hot: 0,
756 | },
757 | {
758 | title: "液晶电视",
759 | hot: 1,
760 | },
761 | {
762 | title: "家电",
763 | hot: 0,
764 | },
765 | {
766 | title: "玩具",
767 | hot: 0,
768 | },
769 | ];
770 |
--------------------------------------------------------------------------------
/src/registerServiceWorker.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { register } from "register-service-worker";
4 |
5 | if (process.env.NODE_ENV === "production") {
6 | register(`${process.env.BASE_URL}service-worker.js`, {
7 | ready() {
8 | console.log(
9 | "App is being served from cache by a service worker.\n" +
10 | "For more details, visit https://goo.gl/AFskqB"
11 | );
12 | },
13 | registered() {
14 | console.log("Service worker has been registered.");
15 | },
16 | cached() {
17 | console.log("Content has been cached for offline use.");
18 | },
19 | updatefound() {
20 | console.log("New content is downloading.");
21 | },
22 | updated() {
23 | console.log("New content is available; please refresh.");
24 | },
25 | offline() {
26 | console.log(
27 | "No internet connection found. App is running in offline mode."
28 | );
29 | },
30 | error(error) {
31 | console.error("Error during service worker registration:", error);
32 | }
33 | });
34 | }
35 |
--------------------------------------------------------------------------------
/src/router/index.ts:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import VueRouter, { RouteConfig } from "vue-router";
3 |
4 | Vue.use(VueRouter);
5 |
6 | const routes: Array = [
7 | {
8 | path: "/",
9 | name: "Home",
10 | component: () =>
11 | import(/* webpackChunkName: "home" */ "../views/home/index.vue"),
12 | meta: {
13 | title: "首页",
14 | headColor: "white",
15 | },
16 | },
17 | {
18 | path: "/login",
19 | name: "Login",
20 | component: () =>
21 | import(/* webpackChunkName: "login" */ "../views/login/index.vue"),
22 | meta: {
23 | title: "登录",
24 | },
25 | },
26 | {
27 | path: "/register",
28 | name: "Register",
29 | component: () =>
30 | import(/* webpackChunkName: "register" */ "../views/register/index.vue"),
31 | meta: {
32 | title: "注册",
33 | },
34 | },
35 | {
36 | path: "/user",
37 | name: "User",
38 | component: () =>
39 | import(/* webpackChunkName: "user" */ "../views/user/index.vue"),
40 | meta: {
41 | title: "个人中心",
42 | },
43 | },
44 | {
45 | path: "/profile",
46 | name: "Profile",
47 | component: () =>
48 | import(/* webpackChunkName: "profile" */ "../views/profile/index.vue"),
49 | meta: {
50 | title: "账号管理",
51 | },
52 | },
53 | {
54 | path: "/product-list",
55 | name: "ProductList",
56 | component: () =>
57 | import(
58 | /* webpackChunkName: "product-list" */ "../views/product-list/index.vue"
59 | ),
60 | meta: {
61 | isHidden: true,
62 | },
63 | },
64 | ];
65 |
66 | const router = new VueRouter({
67 | mode: "history",
68 | base: process.env.BASE_URL,
69 | routes,
70 | });
71 |
72 | export default router;
73 |
--------------------------------------------------------------------------------
/src/shims-tsx.d.ts:
--------------------------------------------------------------------------------
1 | import Vue, { VNode } from "vue";
2 |
3 | declare global {
4 | namespace JSX {
5 | // tslint:disable no-empty-interface
6 | interface Element extends VNode {}
7 | // tslint:disable no-empty-interface
8 | interface ElementClass extends Vue {}
9 | interface IntrinsicElements {
10 | [elem: string]: any;
11 | }
12 | }
13 | interface Window {
14 | toLogin: () => void,
15 | router: any
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module "*.vue" {
2 | import Vue from "vue";
3 | export default Vue;
4 | }
5 |
--------------------------------------------------------------------------------
/src/store/home/index.ts:
--------------------------------------------------------------------------------
1 | import { Commit } from "vuex";
2 | import { HomeState, UserInfoProps } from "./interface";
3 | import {
4 | checkLogin,
5 | userLogin,
6 | LoginParamsProps,
7 | RegisterParamsProps,
8 | userRegister,
9 | logout
10 | } from "../../api/index";
11 |
12 | interface RequestDataProps {
13 | status: number;
14 | msg?: string;
15 | data?: any;
16 | }
17 |
18 | const state: HomeState = {
19 | loginStatus: false,
20 | userInfo: {
21 | answer: "",
22 | createTime: 0,
23 | email: "",
24 | id: 0,
25 | password: "",
26 | phone: "",
27 | question: "",
28 | role: 0,
29 | updateTime: 0,
30 | username: "",
31 | },
32 | };
33 |
34 | const mutations = {
35 | setStatus(state: HomeState, status: boolean) {
36 | state.loginStatus = status;
37 | },
38 | setUserInfo(state: HomeState, info: UserInfoProps) {
39 | state.userInfo = info;
40 | },
41 | };
42 |
43 | const getters = {
44 | loginStatus: (state: HomeState) => state.loginStatus,
45 | userInfo: (state: HomeState) => state.userInfo,
46 | };
47 |
48 | const actions = {
49 | // 判断用户登录状态
50 | async judgeLoginStatus({ commit }: { commit: Commit }) {
51 | const requestData: RequestDataProps = await checkLogin();
52 | commit("setStatus", requestData.status === 0);
53 | commit("setUserInfo", requestData.data);
54 | },
55 |
56 | // 去登陆
57 | async toLogin({ commit }: { commit: Commit }, info: LoginParamsProps) {
58 | const requestData: RequestDataProps = await userLogin(info);
59 | commit("setUserInfo", requestData.data);
60 | if (requestData.status === 0) {
61 | window.router.back();
62 | } else {
63 | alert(requestData.msg);
64 | }
65 | },
66 |
67 | // 注册
68 | async toRegister({ commit }: { commit: Commit }, info: RegisterParamsProps) {
69 | const requestData: RequestDataProps = await userRegister(info);
70 | if (requestData.status === 0) {
71 | window.router.back();
72 | } else {
73 | alert(requestData.msg);
74 | }
75 | },
76 |
77 | // 退出登录
78 | async toLogout({commit}: {commit: Commit}) {
79 | const requestData: RequestDataProps = await logout();
80 | if(requestData.status === 0) {
81 | commit('setStatus', false);
82 | window.router.push({name: 'Home'});
83 | }
84 | }
85 | };
86 |
87 | export default {
88 | state,
89 | getters,
90 | mutations,
91 | actions,
92 | };
93 |
--------------------------------------------------------------------------------
/src/store/home/interface.ts:
--------------------------------------------------------------------------------
1 | export interface HomeState {
2 | loginStatus: boolean;
3 | userInfo: UserInfoProps;
4 | }
5 |
6 | export interface UserInfoProps {
7 | answer: string;
8 | createTime: number;
9 | email: string;
10 | id: number;
11 | password: string;
12 | phone: string;
13 | question: string;
14 | role: number;
15 | updateTime: number;
16 | username: string;
17 | }
18 |
--------------------------------------------------------------------------------
/src/store/index.ts:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import Vuex from "vuex";
3 | import homeModule from "./home/index";
4 | import productModule from './product/index';
5 |
6 | Vue.use(Vuex);
7 |
8 | export default new Vuex.Store({
9 | state: {
10 | ...homeModule.state,
11 | ...productModule.state
12 | },
13 | mutations: {
14 | ...homeModule.mutations,
15 | ...productModule.mutations
16 | },
17 | actions: {
18 | ...homeModule.actions,
19 | ...productModule.actions
20 | },
21 | modules: {}
22 | });
23 |
--------------------------------------------------------------------------------
/src/store/product/index.ts:
--------------------------------------------------------------------------------
1 | import { Commit } from "vuex";
2 | import {
3 | getProductList,
4 | ProductListParams,
5 | getProductDetail,
6 | } from "@/api/index";
7 | import {
8 | ProductState,
9 | ProductItemProps,
10 | ProductDetailProps,
11 | } from "./interface";
12 |
13 | const state: ProductState = {
14 | productList: [],
15 | currentProduct: {
16 | categoryId: 0,
17 | createTime: "",
18 | detail: "",
19 | id: 0,
20 | imageHost: "",
21 | mainImage: "",
22 | name: "",
23 | parentCategoryId: 0,
24 | price: 0,
25 | status: 0,
26 | stock: 0,
27 | subImages: "",
28 | subtitle: "",
29 | updateTime: "",
30 | },
31 | detailShow: false,
32 | };
33 |
34 | const mutations = {
35 | setProductList(state: ProductState, list: Array) {
36 | state.productList = list;
37 | },
38 | setProductInfo(state: ProductState, info: ProductDetailProps) {
39 | state.currentProduct = info;
40 | },
41 | setDetailShow(state: ProductState, bool: boolean) {
42 | state.detailShow = bool;
43 | },
44 | };
45 |
46 | const getters = {
47 | productList: (state: ProductState) => state.productList,
48 | };
49 |
50 | const actions = {
51 | // 获取商品列表
52 | async fetchProductList(
53 | { state, commit }: { state: any; commit: Commit },
54 | { params, loadMore }: { params: ProductListParams; loadMore?: boolean }
55 | ) {
56 | const requestData = await getProductList(params);
57 | const currentData = loadMore
58 | ? state.productList.concat(requestData.data.list)
59 | : requestData.data.list;
60 | commit("setProductList", currentData);
61 | },
62 |
63 | // 获取商品详情
64 | async fetchProductInfo({ commit }: { commit: Commit }, productId: number) {
65 | const requestData = await getProductDetail({ productId });
66 | commit("setDetailShow", true);
67 | commit("setProductInfo", requestData.data);
68 | },
69 | };
70 |
71 | export default {
72 | state,
73 | mutations,
74 | getters,
75 | actions,
76 | };
77 |
--------------------------------------------------------------------------------
/src/store/product/interface.ts:
--------------------------------------------------------------------------------
1 | export interface ProductItemProps {
2 | categoryId?: number;
3 | id: number;
4 | status: number;
5 | imageHost: string;
6 | mainImage: string;
7 | name: string;
8 | subtitle: string;
9 | price: number;
10 | }
11 |
12 | export interface ProductDetailProps {
13 | categoryId: number;
14 | createTime: string;
15 | detail: string;
16 | id: number;
17 | imageHost: string;
18 | mainImage: string;
19 | name: string;
20 | parentCategoryId: number;
21 | price: number;
22 | status: number;
23 | stock: number;
24 | subImages: string;
25 | subtitle: string;
26 | updateTime: string;
27 | }
28 |
29 | export interface ProductState {
30 | productList: Array;
31 | currentProduct: ProductDetailProps;
32 | detailShow: boolean;
33 | }
34 |
--------------------------------------------------------------------------------
/src/utils/http.ts:
--------------------------------------------------------------------------------
1 | import qs from "qs";
2 | import Axios from "axios";
3 | import Vue from "vue";
4 |
5 | // API请求配置
6 | const HTTP = Axios.create({
7 | baseURL: "",
8 | headers: {
9 | "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8"
10 | },
11 | timeout: 30000,
12 | withCredentials: false
13 | });
14 |
15 | // 全局请求发送信息拦截
16 | HTTP.interceptors.request.use(
17 | config => {
18 | if (config.method === "post") {
19 | // if (!config.data.token) {
20 | // config.data.token = window.localStorage.getItem('token');
21 | // }
22 | config.data = qs.stringify(config.data);
23 | }
24 | return config;
25 | },
26 | error => {
27 | throw new Error(error);
28 | }
29 | );
30 |
31 | // 全局请求返回信息拦截
32 | HTTP.interceptors.response.use(
33 | response => {
34 | const data = response.data;
35 | // 未登录or登录超时
36 | // if(data.status == 10) {
37 | // console.log('用户未登录或已超时,请先登录!');
38 | // window.toLogin && window.toLogin();
39 | // }
40 | return data;
41 | },
42 | error => {
43 | if (Vue.prototype.$loading) {
44 | Vue.prototype.$loading.close();
45 | }
46 | throw new Error(error);
47 | }
48 | );
49 |
50 | export default HTTP;
51 |
--------------------------------------------------------------------------------
/src/views/home/components/floor/index.scss:
--------------------------------------------------------------------------------
1 | .home-header {
2 | position: fixed;
3 | left: 0;
4 | top: 0;
5 | @include fj;
6 | width: 100%;
7 | height: 100px;
8 | line-height: 100px;
9 | padding: 0 30px;
10 | @include boxSizing;
11 | font-size: 30px;
12 | color: #fff;
13 | z-index: 10000;
14 |
15 | &.active {
16 | background: $red;
17 | }
18 |
19 | .icon-caidan {
20 | font-size: 50px;
21 | }
22 |
23 | .header-search {
24 | display: flex;
25 | width: 74%;
26 | height: 40px;
27 | line-height: 40px;
28 | margin: 20px 0;
29 | padding: 10px 0;
30 | color: #232326;
31 | background: #fff;
32 | @include borderRadius(40px);
33 |
34 | .app-name {
35 | padding: 0 20px;
36 | color: $red;
37 | font-size: 40px;
38 | font-weight: bold;
39 | border-right: 1px solid #666;
40 | }
41 |
42 | .icon-search {
43 | padding: 0 20px;
44 | font-size: 34px;
45 | }
46 |
47 | .search-title {
48 | font-size: 24px;
49 | color: #666;
50 | }
51 | }
52 |
53 | .icon-iconyonghu {
54 | font-size: 44px;
55 | }
56 | }
57 |
58 | .home-wrap {
59 | width: 100%;
60 | height: 100%;
61 | overflow-y: scroll;
62 | }
63 |
64 | .swiper-container .swiper_img {
65 | height: 400px;
66 | }
67 |
68 | .category-list {
69 | display: flex;
70 | flex-shrink: 0;
71 | flex-wrap: wrap;
72 | width: 100%;
73 | padding-bottom: 26px;
74 |
75 | div {
76 | display: flex;
77 | flex-direction: column;
78 | width: 20%;
79 | text-align: center;
80 |
81 | span {
82 | font-size: 28px;
83 | color: #999;
84 | }
85 |
86 | img {
87 | width: 80px;
88 | height: 80px;
89 | margin: 26px auto 16px auto;
90 | }
91 | }
92 | }
93 |
94 | .floor-list {
95 | width: 100%;
96 |
97 | .floor-head {
98 | width: 100%;
99 | height: 80px;
100 | background: #F6F6F6;
101 | }
102 |
103 | .floor-content {
104 | display: flex;
105 | flex-shrink: 0;
106 | flex-wrap: wrap;
107 | width: 100%;
108 | @include boxSizing;
109 |
110 | .floor-category {
111 | width: 50%;
112 | padding: 20px;
113 | border-right: 1px solid #f5f5f5;
114 | border-bottom: 1px solid #f5f5f5;
115 | @include boxSizing;
116 |
117 | &:nth-child(2n) {
118 | border-right: none;
119 | }
120 |
121 | p {
122 | font-size: 28px;
123 | color: #333;
124 | line-height: 34px;
125 |
126 | &:nth-child(2) {
127 | padding: 10px 0;
128 | font-size: 26px;
129 | color: $red;
130 | }
131 | }
132 |
133 | .floor-products {
134 | display: flex;
135 | justify-content: space-around;
136 | width: 100%;
137 |
138 | img {
139 | width: 130px;
140 | height: 130px;
141 | }
142 | }
143 | }
144 | }
145 | }
--------------------------------------------------------------------------------
/src/views/home/components/floor/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
![]()
5 |
6 |
7 |
{{category.title}}
8 |
{{category.desc}}
9 |
10 |
![]()
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/src/views/home/components/swiper/swiper.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
47 |
48 |
63 |
--------------------------------------------------------------------------------
/src/views/home/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
32 |
--------------------------------------------------------------------------------
/src/views/login/index.scss:
--------------------------------------------------------------------------------
1 | .login-wrap {
2 | width: 100%;
3 | padding: 40px 60px 0 60px;
4 | box-sizing: border-box;
5 |
6 | .login-content {
7 | width: 100%;
8 | margin: 0 auto;
9 | }
10 |
11 | .login-text {
12 | @include fj;
13 | width: 100%;
14 | height: 60px;
15 | line-height: 60px;
16 | padding: 20px 0;
17 | margin-top: 20px;
18 | border-bottom: 1px solid #f5f5f5;
19 |
20 | .iconfont {
21 | font-size: 26px;
22 | color: #CCCCCC;
23 |
24 | &.eye {
25 | padding: 0 30px;
26 | font-size: 40px;
27 | border-right: 1px solid #f5f5f5;
28 | }
29 | }
30 |
31 | input {
32 | width: 100%;
33 | height: 100%;
34 | margin-right: 20px;
35 | line-height: 60px;
36 | color: #222;
37 | font-size: 32px;
38 |
39 | &.login-password {
40 | width: 50%;
41 | }
42 | }
43 |
44 | span {
45 | padding-left: 20px;
46 | font-size: 30px;
47 | }
48 |
49 | div {
50 | display: flex;
51 | }
52 | }
53 | }
54 |
55 | .login-error {
56 | width: 100%;
57 | height: 40px;
58 | line-height: 40px;
59 | padding: 30px 0;
60 | color: $red;
61 | font-size: 26px;
62 | }
63 |
64 | .login-button {
65 | width: 100%;
66 | height: 100px;
67 | text-align: center;
68 | line-height: 100px;
69 | color: #fff;
70 | font-size: 32px;
71 | background: rgba(246, 53, 21, .5);
72 | @include borderRadius(60px);
73 |
74 | &.active {
75 | background: rgb(246, 53, 21)
76 | }
77 | }
78 |
79 | .quick-nav {
80 | @include fj;
81 | padding: 40px 0;
82 | width: 100%;
83 |
84 | span {
85 | color: #999;
86 | font-size: 28px;
87 | }
88 | }
89 |
90 | .other-login {
91 | width: 100%;
92 | margin-top: 100px;
93 |
94 | .other-head {
95 | @include fj;
96 |
97 | i {
98 | flex: 1;
99 | height: 1px;
100 | margin-top: 18px;
101 | background: #dcdcdc;
102 | }
103 |
104 | span {
105 | flex: 1;
106 | text-align: center;
107 | font-size: 28px;
108 | color: #dcdcdc;
109 | }
110 | }
111 |
112 | .other-con {
113 | display: flex;
114 | width: 320px;
115 | padding: 40px 0;
116 | margin: 0 auto;
117 |
118 | .login-icon {
119 | display: flex;
120 | flex-direction: column;
121 | width: 96px;
122 | margin: 0 30px;
123 | text-align: center;
124 |
125 | .iconfont {
126 | width: 100%;
127 | height: 96px;
128 | line-height: 96px;
129 | font-size: 60px;
130 | color: #15B8F5;
131 | background: #E7F7FE;
132 | @include borderRadius(50%);
133 |
134 | &.icon-weixin1 {
135 | font-size: 50px;
136 | color: #09BB07;
137 | background: #E6F8E6;
138 | }
139 | }
140 |
141 | span {
142 | padding-top: 20px;
143 | color: #999;
144 | }
145 | }
146 | }
147 |
148 | p {
149 | margin-top: 20px;
150 | width: 100%;
151 | text-align: center;
152 | color: #999;
153 |
154 | a {
155 | color: #409eff;
156 | }
157 | }
158 | }
--------------------------------------------------------------------------------
/src/views/login/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | 快速注册
14 | 忘记密码
15 |
16 |
17 |
18 |
19 |
20 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/src/views/product-detail/components/detail-con.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | - 概述
19 | - 参数
20 | - 安装服务
21 | - 常见问题
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
31 | 喜欢
32 |
33 |
34 |
35 | 购物车
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
71 |
72 |
--------------------------------------------------------------------------------
/src/views/product-detail/components/head.vue:
--------------------------------------------------------------------------------
1 |
2 |
17 |
18 |
19 |
42 |
43 |
--------------------------------------------------------------------------------
/src/views/product-detail/index.scss:
--------------------------------------------------------------------------------
1 | .product-detail {
2 | display: flex;
3 | flex-direction: column;
4 | position: fixed;
5 | left: 0;
6 | top: 0;
7 | right: 0;
8 | bottom: 0;
9 | background-color: #fff;
10 | z-index: 20;
11 | overflow: hidden;
12 |
13 | .detail-nav {
14 | @include fj;
15 | width: 100%;
16 | height: 88px;
17 | padding: 0 20px;
18 | line-height: 88px;
19 | box-sizing: border-box;
20 | z-index: 1000;
21 | color: #252525;
22 | background: #fff;
23 | border-bottom: 1px solid #dcdcdc;
24 |
25 | i {
26 | font-size: 50px;
27 | color: #000;
28 | }
29 |
30 | div span {
31 | padding: 0 20px;
32 | font-size: 28px;
33 |
34 | &.active {
35 | color: $red;
36 | }
37 |
38 | .iconfont {
39 | padding-right: 8px;
40 | font-size: 28px;
41 | color: $red;
42 | }
43 | }
44 | }
45 |
46 | .detail-con {
47 | width: 100%;
48 | height: 100%;
49 | overflow-y: scroll;
50 | }
51 |
52 | .detail-slider img {
53 | height: 700px;
54 | }
55 |
56 |
57 | .detail-info {
58 | width: 100%;
59 | padding: 20px 30px;
60 | font-size: 30px;
61 | box-sizing: border-box;
62 |
63 | .detail-info-name {
64 | font-size: 40px;
65 | color: #333;
66 | }
67 |
68 | .detail-info-subtitle {
69 | padding: 10px 0;
70 | font-size: 28px;
71 | color: #999;
72 | }
73 |
74 | div {
75 | @include fj;
76 | padding: 10px 0;
77 | font-size: 32px;
78 | color: #999;
79 |
80 | .detail-info-price {
81 | color: $red;
82 | font-size: 44px;
83 | }
84 | }
85 | }
86 |
87 | .detail-content {
88 | width: 100%;
89 |
90 | .detail-gap {
91 | width: 100%;
92 | height: 20px;
93 | background: #eee;
94 | }
95 |
96 | ul {
97 | @include fj;
98 | width: 100%;
99 | margin: 20px 0;
100 |
101 | li {
102 | flex: 1;
103 | padding: 10px 0;
104 | text-align: center;
105 | font-size: 30px;
106 | border-right: 1px solid #999;
107 | box-sizing: border-box;
108 |
109 | &:last-child {
110 | border-right: none;
111 | }
112 | }
113 | }
114 |
115 | div {
116 | width: 100%;
117 | overflow: hidden;
118 |
119 | p {
120 | width: 100%;
121 | font-size: 40px;
122 | text-align: center;
123 | }
124 |
125 | img {
126 | width: 100%;
127 | }
128 | }
129 | }
130 |
131 | .detail-cart {
132 | @include fj;
133 | position: fixed;
134 | left: 0;
135 | bottom: 0;
136 | width: 100%;
137 | height: 100px;
138 | line-height: 100px;
139 | font-size: 30px;
140 | background: #FEFBF9;
141 | z-index: 1000;
142 | transform: translateZ(0);
143 | -webkit-transform: translateZ(0);
144 | @include boxSizing;
145 |
146 | .detail-cart-left {
147 | @include fj;
148 | width: 46%;
149 | padding: 0 30px;
150 | @include boxSizing;
151 |
152 | .like {
153 | width: 40%;
154 | display: flex;
155 | flex-direction: column;
156 | text-align: center;
157 |
158 | .iconfont {
159 | font-size: 34px;
160 | line-height: 60px;
161 | color: #000000;
162 | font-weight: bold;
163 |
164 | &.icon-love {
165 | color: $red;
166 | }
167 | }
168 |
169 | span {
170 | line-height: 30px;
171 | font-size: 26px;
172 | }
173 | }
174 |
175 | .cart {
176 | @extend .like;
177 | position: relative;
178 |
179 | .cart-num {
180 | position: absolute;
181 | right: 20px;
182 | top: 0;
183 | width: 30px;
184 | height: 30px;
185 | text-align: center;
186 | line-height: 30px;
187 | color: #fff;
188 | font-size: 22px;
189 | background: $red;
190 | @include borderRadius(50%);
191 | }
192 |
193 | .iconfont {
194 | font-size: 40px;
195 | font-weight: normal;
196 | }
197 | }
198 | }
199 |
200 | .detail-cart-right {
201 | width: 54%;
202 |
203 | button {
204 | width: 100%;
205 | height: 100px;
206 | color: #fff;
207 | font-size: 30px;
208 | background: $red;
209 |
210 | &:nth-child(1) {
211 | margin-right: -10px;
212 | background: rgba(246, 53, 21, .9);
213 | }
214 | }
215 | }
216 | }
217 |
218 | .modal {
219 | position: fixed;
220 | left: 0;
221 | top: 0;
222 | width: 100%;
223 | height: 100%;
224 | z-index: 1000;
225 | background: rgba(0, 0, 0, .6);
226 | }
227 |
228 | .cart-wrap {
229 | position: fixed;
230 | left: 0;
231 | bottom: 0;
232 | width: 100%;
233 | height: 60%;
234 | z-index: 99999999;
235 |
236 | .cart-content {
237 | position: absolute;
238 | left: 0;
239 | bottom: 0;
240 | width: 100%;
241 | height: 100%;
242 | font-size: 30px;
243 | background: #fff;
244 |
245 | .cart-head {
246 | display: flex;
247 | width: 100%;
248 | padding: 30px;
249 | @include boxSizing;
250 |
251 | img {
252 | width: 180px;
253 | height: 180px;
254 | margin-top: -60px;
255 | border: 1px solid #999;
256 | }
257 |
258 | div {
259 | display: flex;
260 | flex-direction: column;
261 | justify-content: space-between;
262 | width: 64%;
263 | margin-left: 20px;
264 |
265 | .price {
266 | display: block;
267 | font-size: 34px;
268 | color: $red;
269 | padding-bottom: 10px;
270 | }
271 |
272 | p {
273 | max-height: 40px;
274 | overflow: hidden;
275 | }
276 | }
277 |
278 | .iconfont {
279 | position: absolute;
280 | top: 30px;
281 | right: 30px;
282 | font-size: 28px;
283 | color: #dcdcdc;
284 | }
285 | }
286 |
287 | .cart-config {
288 | @extend .cart-head;
289 | padding: 0 30px 30px 30px;
290 |
291 | .subtitle {
292 | width: 100%;
293 | margin-left: 0;
294 | padding: 20px 0;
295 |
296 | span {
297 | &:first-child {
298 | color: #999;
299 | padding-bottom: 20px;
300 | }
301 | }
302 | }
303 | }
304 |
305 | .cart-count {
306 | @include fj;
307 | width: 100%;
308 | padding: 0 30px 30px 30px;
309 | @include boxSizing;
310 |
311 | .cart-quantity {
312 | @include fj;
313 | width: 210px;
314 | height: 60px;
315 | line-height: 60px;
316 | color: #999;
317 | background: #fff;
318 |
319 | span {
320 | width: 80px;
321 | height: 100%;
322 | text-align: center;
323 | line-height: 60px;
324 | background: #F7F7F7;
325 | }
326 |
327 | i {
328 | width: 60px;
329 | height: 100%;
330 | text-align: center;
331 | line-height: 60px;
332 | font-style: normal;
333 | font-size: 50px;
334 | background: #F7F7F7;
335 |
336 | &.active {
337 | color: #dcdcdc;
338 | }
339 | }
340 | }
341 | }
342 |
343 | .add-cart {
344 | position: absolute;
345 | left: 0;
346 | bottom: 0;
347 | width: 100%;
348 | height: 100px;
349 | text-align: center;
350 | line-height: 100px;
351 | color: #fff;
352 | font-size: 30px;
353 | background: $red;
354 | }
355 | }
356 | }
357 |
358 | .slide-up-enter-active,
359 | .slide-up-leave-active {
360 | transition: all 0.5s;
361 | }
362 |
363 | .slide-up-enter,
364 | .slide-up-leave-to {
365 | transform: translate3d(0, 100%, 0);
366 | }
367 | }
--------------------------------------------------------------------------------
/src/views/product-detail/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
32 |
33 |
--------------------------------------------------------------------------------
/src/views/product-list/component/list-item/index.vue:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Rosen97/web-shop/93dfb95e2fd232ae46363f51f69fcbe25e6fb357/src/views/product-list/component/list-item/index.vue
--------------------------------------------------------------------------------
/src/views/product-list/component/search-head/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/views/product-list/component/select-tab/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |
20 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/src/views/product-list/index.scss:
--------------------------------------------------------------------------------
1 | .product-wrap {
2 | display: flex;
3 | flex-direction: column;
4 | width: 100%;
5 | height: 100vh;
6 | overflow: hidden;
7 | }
8 |
9 | .category-header {
10 | @include fj;
11 | width: 100%;
12 | height: 100px;
13 | line-height: 100px;
14 | padding: 0 30px;
15 | @include boxSizing;
16 | font-size: 30px;
17 | color: #656771;
18 | z-index: 10;
19 |
20 | &.active {
21 | background: $red;
22 | }
23 |
24 | .icon-left {
25 | font-size: 50px;
26 | font-weight: bold;
27 | }
28 |
29 | .header-search {
30 | display: flex;
31 | width: 76%;
32 | height: 40px;
33 | line-height: 40px;
34 | margin: 20px 0;
35 | padding: 10px 0;
36 | color: #232326;
37 | background: #F7F7F7;
38 | @include borderRadius(40px);
39 |
40 | .icon-search {
41 | padding: 0 10px 0 40px;
42 | font-size: 34px;
43 | }
44 |
45 | .search-title {
46 | font-size: 24px;
47 | color: #666;
48 | background: #F7F7F7;
49 | }
50 | }
51 |
52 | .icon-More {
53 | font-size: 40px;
54 | }
55 |
56 | .search-btn {
57 | height: 70px;
58 | margin: 15px 0;
59 | line-height: 70px;
60 | padding: 0 20px;
61 | color: #fff;
62 | background: $red;
63 | @include borderRadius(10px);
64 | }
65 | }
66 |
67 | .select-menu {
68 | display: flex;
69 | justify-content: space-around;
70 | width: 100%;
71 | height: 100px;
72 | background: #fff;
73 |
74 | &.isFixed {
75 | position: fixed;
76 | left: 0;
77 | top: 0;
78 | }
79 |
80 | .select-item {
81 | flex: 1;
82 | height: 100%;
83 | text-align: center;
84 | line-height: 100px;
85 | font-size: 30px;
86 | border-top: 1px solid #dcdcdc;
87 | border-bottom: 1px solid #dcdcdc;
88 |
89 | &.active {
90 | color: $red;
91 | }
92 |
93 | .iconfont {
94 | &.icon-down1 {
95 | color: #999;
96 | padding-left: 10px;
97 | font-size: 22px;
98 | }
99 |
100 | &.icon-up1 {
101 | @extend .icon-down1;
102 | font-size: 34px;
103 | }
104 |
105 | &.icon-shaixuan {
106 | @extend .icon-down1;
107 | font-size: 28px;
108 | }
109 |
110 | &.active {
111 | color: $red;
112 | }
113 | }
114 | }
115 | }
116 |
117 | .loading {
118 | position: relative;
119 | width: 100%;
120 | height: 100%;
121 |
122 | img {
123 | position: absolute;
124 | left: 50%;
125 | top: 50%;
126 | width: 100px;
127 | height: 100px;
128 | transform: translate(-50%, -50%);
129 | }
130 | }
131 |
132 | .product-list {
133 | width: 100%;
134 | height: 100%;
135 | overflow-y: scroll;
136 |
137 | .product-item {
138 | @include fj;
139 | width: 100%;
140 | height: 240px;
141 | padding: 20px 0;
142 | border-bottom: 1px solid #dcdcdc;
143 |
144 | img {
145 | width: 280px;
146 | height: 240px;
147 | padding: 0 20px;
148 | @include boxSizing;
149 | }
150 |
151 | .product-info {
152 | width: 56%;
153 | height: 240px;
154 | padding: 10px;
155 | @include boxSizing;
156 |
157 | .name {
158 | width: 100%;
159 | max-height: 80px;
160 | line-height: 40px;
161 | font-size: 30px;
162 | color: #333;
163 | overflow: hidden;
164 | }
165 |
166 | .subtitle {
167 | width: 100%;
168 | max-height: 40px;
169 | padding: 20px 0;
170 | line-height: 50px;
171 | font-size: 26px;
172 | color: #999;
173 | overflow: hidden;
174 | }
175 |
176 | .price {
177 | color: $red;
178 | font-size: 32px;
179 | }
180 | }
181 | }
182 | }
183 |
184 | .fade-enter-active,
185 | .fade-leave-active {
186 | transition: opacity .5s;
187 | }
188 |
189 | .fade-enter,
190 | .fade-leave-to {
191 | opacity: 0;
192 | }
--------------------------------------------------------------------------------
/src/views/product-list/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
{{productParams.num}}
9 |
10 |
20 |
21 |
22 |
23 |
24 |
106 |
107 |
108 |
--------------------------------------------------------------------------------
/src/views/profile/component/profile-foot/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
19 |
20 |
21 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/src/views/profile/component/profile-info/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

6 |
7 | {{userInfo.username}}
8 | 邮箱:{{userInfo.email}}
9 |
10 |
11 |
12 |
13 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/views/profile/index.scss:
--------------------------------------------------------------------------------
1 | .user-head {
2 | @include fj;
3 | width: 100%;
4 | height: 88px;
5 | padding: 0 20px;
6 | line-height: 88px;
7 | font-size: 30px;
8 | @include boxSizing;
9 | border-bottom: 1px solid #f7f7f7;
10 |
11 | .iconfont {
12 | font-size: 44px;
13 | }
14 | }
15 |
16 | .profile-content {
17 | width: 100%;
18 |
19 | .profile-title {
20 | width: 100%;
21 | padding: 30px;
22 | @include boxSizing;
23 | font-weight: normal;
24 | color: #999;
25 | border-bottom: 1px solid #f7f7f7;
26 | }
27 |
28 | .profile-item {
29 | @extend .profile-title;
30 | @include fj;
31 | color: #999;
32 | font-size: 30px;
33 |
34 | &.info {
35 | justify-content: left;
36 |
37 | img {
38 | width: 100px;
39 | height: 100px;
40 | @include borderRadius(50%);
41 | }
42 |
43 | div {
44 | display: flex;
45 | flex-direction: column;
46 | justify-content: space-between;
47 | padding-left: 30px;
48 | font-size: 30px;
49 | color: #666;
50 |
51 | span:last-child {
52 | color: #999;
53 | }
54 | }
55 | }
56 |
57 | .iconfont {
58 | font-size: 38px;
59 | }
60 | }
61 | }
62 |
63 | .profile-footer {
64 | width: 100%;
65 | margin-top: 200px;
66 |
67 | .footer-con {
68 | display: flex;
69 | width: 100%;
70 |
71 | div {
72 | flex: 1;
73 | height: 40px;
74 | text-align: center;
75 | line-height: 34px;
76 | font-size: 26px;
77 | color: #333;
78 |
79 | &.client {
80 | line-height: 50px;
81 | }
82 |
83 | &.logout {
84 | line-height: 44px;
85 | }
86 |
87 | i {
88 | font-style: normal;
89 | font-size: 30px;
90 | color: #999;
91 |
92 | &.iconfont {
93 | font-size: 44px;
94 | }
95 | }
96 | }
97 | }
98 |
99 | .mmall {
100 | width: 100%;
101 | margin-top: 140px;
102 | text-align: center;
103 | font-size: 50px;
104 | color: $red;
105 | }
106 | }
--------------------------------------------------------------------------------
/src/views/profile/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
当前登录账号
5 |
6 |
13 | {{item.name}}
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/src/views/register/index.scss:
--------------------------------------------------------------------------------
1 | .register-page {
2 | width: 100%;
3 | padding: 0 30px;
4 | margin-top: 60px;
5 | box-sizing: border-box;
6 |
7 | .register-wrap {
8 | width: 100%;
9 |
10 | .register-text {
11 | @include fj;
12 | width: 100%;
13 | height: 60px;
14 | line-height: 60px;
15 | padding: 20px 0;
16 | margin-top: 20px;
17 | border-bottom: 1px solid #dcdcdc;
18 |
19 | .iconfont {
20 | font-size: 26px;
21 | color: #CCCCCC;
22 |
23 | &.eye {
24 | padding: 0 30px;
25 | font-size: 40px;
26 | border-right: 1px solid #dcdcdc;
27 | }
28 | }
29 |
30 | input {
31 | width: 100%;
32 | height: 100%;
33 | margin-right: 20px;
34 | line-height: 60px;
35 | color: #222;
36 | font-size: 32px;
37 | }
38 |
39 | span {
40 | padding-left: 20px;
41 | font-size: 30px;
42 | }
43 |
44 | div {
45 | display: flex;
46 | }
47 | }
48 | }
49 | }
50 |
51 | .register-error {
52 | width: 100%;
53 | height: 40px;
54 | line-height: 40px;
55 | padding: 30px 0;
56 | color: $red;
57 | font-size: 26px;
58 | }
59 |
60 | .register-button {
61 | width: 100%;
62 | height: 100px;
63 | text-align: center;
64 | line-height: 100px;
65 | color: #fff;
66 | font-size: 32px;
67 | background: rgba(246, 53, 21, .5);
68 | @include borderRadius(60px);
69 |
70 | &.active {
71 | background: rgb(246, 53, 21)
72 | }
73 | }
74 |
75 | .set-security {
76 | position: fixed;
77 | left: 0;
78 | top: 0;
79 | width: 100%;
80 | height: 100%;
81 | padding: 0 30px;
82 | z-index: 100;
83 | background: #fff;
84 | @include boxSizing;
85 |
86 | p {
87 | font-size: 30px;
88 | color: #999;
89 | padding-top: 30px;
90 | }
91 |
92 | .set-security-head {
93 | position: relative;
94 | width: 100%;
95 | height: 88px;
96 | text-align: center;
97 | line-height: 88px;
98 | font-size: 34px;
99 | @include boxSizing;
100 |
101 | .iconfont {
102 | position: absolute;
103 | left: 0;
104 | top: 0;
105 | font-size: 50px;
106 | font-weight: bold;
107 | }
108 | }
109 | }
110 |
111 | .slide-enter-active,
112 | .slide-leave-active {
113 | transition: all 0.5s;
114 | }
115 |
116 | .slide-enter,
117 | .slide-leave-to {
118 | transform: translate3d(100%, 0, 0);
119 | }
--------------------------------------------------------------------------------
/src/views/register/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/src/views/user/components/head-info/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |

7 |
8 |
{{userInfo.username}}
9 |
用户名:{{userInfo.username}}
10 |
{{userInfo.phone}}
11 |
12 |
13 | 账号管理
14 |
15 |
16 |
17 |
18 |
19 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/src/views/user/components/tab-list/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
14 |
15 |
16 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/src/views/user/index.scss:
--------------------------------------------------------------------------------
1 | .user-wrap {
2 | background: #F7F7F7;
3 |
4 | .user-head {
5 | @include fj;
6 | width: 100%;
7 | height: 88px;
8 | padding: 0 20px;
9 | line-height: 88px;
10 | font-size: 30px;
11 | @include boxSizing;
12 | border-bottom: 1px solid #dcdcdc;
13 |
14 | .iconfont {
15 | font-size: 44px;
16 | }
17 | }
18 |
19 | .user-info {
20 | width: 94%;
21 | margin: 20px 3%;
22 | height: 230px;
23 | background: linear-gradient(90deg, #eb3c3c, #ff7459);
24 | box-shadow: 0 2px 5px rgba(255, 98, 98, .4);
25 | @include borderRadius(12px);
26 |
27 | .info {
28 | position: relative;
29 | display: flex;
30 | width: 100%;
31 | height: 100%;
32 | padding: 50px 30px;
33 | @include boxSizing;
34 |
35 | img {
36 | width: 120px;
37 | height: 120px;
38 | }
39 |
40 | div {
41 | display: flex;
42 | flex-direction: column;
43 | margin-left: 20px;
44 | line-height: 40px;
45 | font-size: 28px;
46 | color: #fff;
47 |
48 | .name {
49 | color: hsla(0, 0%, 100%, .7);
50 | font-size: 26px;
51 | padding: 5px 0;
52 | }
53 |
54 | span {
55 | &:nth-child(1) {
56 | color: #999;
57 | font-size: 26px;
58 | }
59 | }
60 | }
61 |
62 | .account-management {
63 | position: absolute;
64 | top: 20px;
65 | right: 40px;
66 | font-size: 26px;
67 | color: rgba(76, 0, 0, .7);
68 |
69 | .iconfont {
70 | padding-right: 10px;
71 | font-size: 28px;
72 | color: rgba(76, 0, 0, .7);
73 | }
74 | }
75 | }
76 | }
77 |
78 | .user-menu {
79 | display: flex;
80 | justify-content: space-around;
81 | width: 100%;
82 | height: 150px;
83 | background: #fff;
84 |
85 | .menu-item {
86 | display: flex;
87 | flex-direction: column;
88 | flex: 1;
89 | height: 100px;
90 | text-align: center;
91 | margin: 25px 0;
92 |
93 | .iconfont {
94 | font-size: 50px;
95 | color: #DD9E58;
96 |
97 | &.icon-money {
98 | font-size: 44px;
99 | padding-top: 6px;
100 | }
101 |
102 | &.icon-icon1 {
103 | @extend .icon-money;
104 | color: $red;
105 | }
106 | }
107 |
108 | span {
109 | padding-top: 10px;
110 | font-size: 24px;
111 | color: #000;
112 | }
113 | }
114 | }
115 |
116 | .user-fork {
117 | margin: 30px 0;
118 | @extend .user-menu;
119 |
120 | .fork-item {
121 | display: flex;
122 | flex-direction: column;
123 | flex: 1;
124 | height: 100px;
125 | margin: 30px 0;
126 | text-align: center;
127 |
128 | i {
129 | font-style: normal;
130 | font-weight: bold;
131 | padding: 10px 0;
132 | font-size: 28px;
133 | }
134 | }
135 | }
136 |
137 | .recommend-title {
138 | width: 100%;
139 | height: 90px;
140 | padding-left: 20px;
141 | line-height: 90px;
142 | background: #fff;
143 | @include boxSizing;
144 | }
145 |
146 | .recommend-list {
147 | display: flex;
148 | flex-shrink: 0;
149 | flex-wrap: wrap;
150 | width: 100%;
151 | margin-top: 30px;
152 | padding-bottom: 150px;
153 | @include boxSizing;
154 | background: #fff;
155 |
156 | .recommend-item {
157 | display: flex;
158 | flex-direction: column;
159 | width: 50%;
160 | padding: 20px;
161 | @include boxSizing;
162 | border-bottom: 1px solid #dcdcdc;
163 |
164 | &:nth-child(2n-1) {
165 | border-right: 1px solid #dcdcdc;
166 | }
167 |
168 | img {
169 | width: 100%;
170 | height: 290px;
171 | margin: 0 auto;
172 | }
173 |
174 | p {
175 | height: 60px;
176 | padding: 20px 0;
177 | font-size: 26px;
178 | line-height: 40px;
179 | color: #333;
180 | overflow: hidden;
181 | }
182 |
183 | i {
184 | font-style: normal;
185 | font-size: 32px;
186 | color: $red;
187 | }
188 | }
189 | }
190 | }
--------------------------------------------------------------------------------
/src/views/user/index.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strictPropertyInitialization": false,
4 | "target": "esnext",
5 | "module": "esnext",
6 | "strict": true,
7 | "jsx": "preserve",
8 | "importHelpers": true,
9 | "moduleResolution": "node",
10 | "experimentalDecorators": true,
11 | "esModuleInterop": true,
12 | "allowSyntheticDefaultImports": true,
13 | "sourceMap": true,
14 | "baseUrl": ".",
15 | "types": [
16 | "webpack-env"
17 | ],
18 | "paths": {
19 | "@/*": [
20 | "src/*"
21 | ]
22 | },
23 | "lib": [
24 | "esnext",
25 | "dom",
26 | "dom.iterable",
27 | "scripthost"
28 | ]
29 | },
30 | "include": [
31 | "src/**/*.ts",
32 | "src/**/*.tsx",
33 | "src/**/*.vue",
34 | "tests/**/*.ts",
35 | "tests/**/*.tsx"
36 | ],
37 | "exclude": [
38 | "node_modules"
39 | ]
40 | }
41 |
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const path = require('path');
3 | const CompressionPlugin = require('compression-webpack-plugin');
4 |
5 | const isProduction = process.env.NODE_ENV !== 'development';
6 |
7 | const setPath = url => path.resolve(__dirname, url);
8 |
9 | let url = ''; // 请求接口地址
10 | let buriedPointUrl = ''; // 埋点接口地址
11 |
12 | module.exports = {
13 | publicPath: '/',
14 | outputDir: 'dist',
15 | assetsDir: 'static',
16 | productionSourceMap: false,
17 | chainWebpack: (config) => {
18 | // 修复HMR
19 | config.resolve.symlinks(true);
20 | // 删除预加载
21 | config.plugins.delete('prefetch');
22 | config.plugins.delete('preload');
23 | },
24 | configureWebpack: {
25 | entry: {
26 | app: './src/main.ts'
27 | },
28 | plugins: [
29 | new CompressionPlugin({
30 | test: /\.js$|\.html$|.\css/, // 匹配文件名
31 | threshold: 10240, // 对超过10k的数据压缩
32 | deleteOriginalAssets: false, // 不删除源文件
33 | }),
34 | (compiler) => {
35 | compiler.hooks.done.tap('vue-cli-service build', (stats) => {
36 | // 打包时把配置文件抽成单独的json文件
37 | const userConfig = require(`./src/config/index.ts`);
38 | userConfig.url = {
39 | // 接口请求地址
40 | http: url,
41 | // 埋点请求地址
42 | buriedPoint: buriedPointUrl,
43 | };
44 | userConfig.debug = !!process.env.npm_config_debug;
45 | try {
46 | fs.accessSync(setPath('dist'), fs.constants.F_OK);
47 | } catch (e) {
48 | fs.mkdirSync(setPath('dist'));
49 | }
50 | fs.writeFileSync(
51 | path.join(__dirname, 'dist', 'config.json'),
52 | JSON.stringify(userConfig, null, '\t'),
53 | 'utf8',
54 | );
55 | });
56 | }
57 | ]
58 | },
59 | css: {
60 | loaderOptions: {
61 | sass: {
62 | prependData: `@import "src/assets/styles/index.scss";`
63 | }
64 | }
65 | },
66 | // css: {
67 | // extract: isProduction,
68 | // sourceMap: false,
69 | // requireModuleExtension: false,
70 | // // 全局引入mixin.scss
71 | // loaderOptions: {
72 | // sass: {
73 | // prependData: `@import "src/assets/styles/index.scss";`
74 | // }
75 | // },
76 | // },
77 | parallel: require('os').cpus().length > 1,
78 | devServer: {
79 | port: 8008,
80 | open: false,
81 | compress: false,
82 | overlay: {
83 | warnings: false,
84 | errors: true,
85 | },
86 | proxy: 'http://test.happymmall.com',
87 | },
88 | };
--------------------------------------------------------------------------------