├── .browserslistrc ├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── LICENSE ├── ProjectNote.md ├── README.md ├── babel.config.js ├── package-lock.json ├── package.json ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── assets │ ├── bk.jpg │ ├── css │ │ ├── base.css │ │ └── global.css │ ├── fonts │ │ ├── demo.css │ │ ├── demo_fontclass.html │ │ ├── demo_symbol.html │ │ ├── demo_unicode.html │ │ ├── iconfont.css │ │ ├── iconfont.eot │ │ ├── iconfont.js │ │ ├── iconfont.svg │ │ ├── iconfont.ttf │ │ └── iconfont.woff │ ├── heima.png │ ├── logo.png │ └── manager.jpg ├── common │ ├── mixin.js │ ├── utils.js │ └── webClick.js ├── components │ ├── content │ │ └── breadcrumb │ │ │ └── Breadcrumb.vue │ ├── home │ │ ├── Home.vue │ │ ├── goods │ │ │ ├── cate │ │ │ │ └── Cate.vue │ │ │ ├── list │ │ │ │ ├── List.vue │ │ │ │ └── children │ │ │ │ │ └── Add.vue │ │ │ └── params │ │ │ │ └── Params.vue │ │ ├── order │ │ │ ├── Order.vue │ │ │ └── citydata.js │ │ ├── power │ │ │ ├── rights │ │ │ │ └── Rights.vue │ │ │ └── roles │ │ │ │ └── Roles.vue │ │ ├── report │ │ │ └── Report.vue │ │ ├── users │ │ │ └── Users.vue │ │ └── welcome │ │ │ └── Welcome.vue │ └── login │ │ └── Login.vue ├── main-dev.js ├── main-prod.js ├── plugins │ └── element.js └── router │ └── index.js ├── vue.config.js └── 电商管理后台 API 接口文档.md /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | trim_trailing_whitespace = true 5 | insert_final_newline = true 6 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | extends: [ 7 | 'plugin:vue/essential', 8 | '@vue/standard' 9 | ], 10 | parserOptions: { 11 | parser: 'babel-eslint' 12 | }, 13 | rules: { 14 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 15 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 16 | 'space-before-function-paren': 0, 17 | "no-unused-vars":"off", 18 | 'no-undef': 'off', 19 | "no-useless-return": "off", 20 | "no-unused-vars": 0 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "printWidth": 200 5 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | <<<<<<< HEAD 2 | MIT License 3 | 4 | Copyright (c) 2021 lysimportant 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | ======= 24 | MIT License 25 | 26 | Copyright (c) 2021 lysimportant 27 | 28 | Permission is hereby granted, free of charge, to any person obtaining a copy 29 | of this software and associated documentation files (the "Software"), to deal 30 | in the Software without restriction, including without limitation the rights 31 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 32 | copies of the Software, and to permit persons to whom the Software is 33 | furnished to do so, subject to the following conditions: 34 | 35 | The above copyright notice and this permission notice shall be included in all 36 | copies or substantial portions of the Software. 37 | 38 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 39 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 40 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 41 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 42 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 43 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 44 | SOFTWARE. 45 | >>>>>>> 7822239992d16a9907835eb6da22a7bae2b347c6 46 | -------------------------------------------------------------------------------- /ProjectNote.md: -------------------------------------------------------------------------------- 1 | * http 是无状态的 2 | * 通过 cookie 在客户端记录状态 3 | * 通过 session 在服务器端记录状态 4 | * 通过 token 方式维持状态 5 | * 前端与服务器之间存在跨域问题时使用 6 | * 登录前输入帐号、密码 -》 服务器验证后返回token -》 客户端保存token -》 后续请求都携带token数据发送请求(用户的验证) -》 服务器验证token是否通过 7 | ## 项目准备工作 8 | * 开始项目前创建一个分支来书写 写完成后在合并分支 `git checkout -b name` :创建一个名为name的分支 9 | * 清空不必要的文件 10 | 11 | ---- 12 | 1. 创建一个Login组件(三标签) : `template`(一: 模板) `script`(二: 属性/方法) ` 16 | -------------------------------------------------------------------------------- /src/assets/bk.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lysimportant/vue_shop/c9a9ca0b08cdf850b8fc1ee1b3732b13302f5007/src/assets/bk.jpg -------------------------------------------------------------------------------- /src/assets/css/base.css: -------------------------------------------------------------------------------- 1 | /* 把我们所有标签的内外边距清零 */ 2 | * { 3 | margin: 0; 4 | padding: 0; 5 | /* CSS3 盒子模型 */ 6 | box-sizing: border-box; 7 | } 8 | /* em 和 i 斜体的文字不倾斜 */ 9 | em, 10 | i { 11 | font-style: normal; 12 | } 13 | /* 去掉li 的小圆点 */ 14 | li { 15 | list-style: none; 16 | } 17 | 18 | img { 19 | /* border 0 照顾低版本浏览器 如果 图片外面包含了链接会有边框的问题 */ 20 | border: 0; 21 | /* 取消图片底侧有空白缝隙的问题 */ 22 | vertical-align: middle; 23 | } 24 | 25 | button { 26 | /* 当我们鼠标经过button 按钮的时候,鼠标变成小手 */ 27 | cursor: pointer; 28 | border: 0; 29 | } 30 | 31 | a { 32 | color: #666; 33 | text-decoration: none; 34 | } 35 | 36 | a:hover { 37 | color: black; 38 | } 39 | 40 | button, 41 | input { 42 | /* "\5B8B\4F53" 就是宋体的意思 这样浏览器兼容性比较好 */ 43 | font-family: Microsoft YaHei, Heiti SC, tahoma, arial, Hiragino Sans GB, '\5B8B\4F53', sans-serif; 44 | /* 默认有灰色边框需要手动抹掉 */ 45 | border: 0; 46 | /* 点击input默认的蓝色边框去掉 */ 47 | outline: none; 48 | } 49 | 50 | body { 51 | /* CSS3 抗锯齿形 让文字显示的更加清晰 */ 52 | -webkit-font-smoothing: antialiased; 53 | background-color: #fff; 54 | font: 12px/1.5 Microsoft YaHei, Heiti SC, tahoma, arial, Hiragino Sans GB, '\5B8B\4F53', sans-serif; 55 | color: #666; 56 | } 57 | 58 | .hide, 59 | .none { 60 | display: none; 61 | } 62 | /* 清除浮动 */ 63 | .clearfix:before, 64 | .clearfix:after { 65 | content: ''; 66 | display: table; 67 | /*转换成表格*/ 68 | } 69 | 70 | .clearfix:after { 71 | clear: both; 72 | } 73 | 74 | .clearfix { 75 | *zoom: 1; 76 | } 77 | -------------------------------------------------------------------------------- /src/assets/css/global.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | #app { 4 | margin: 0; 5 | padding: 0; 6 | height: 100%; 7 | min-width: 1366px; 8 | } 9 | .el-breadcrumb { 10 | margin-bottom: 15px; 11 | font-size: 12px; 12 | } 13 | .el-card { 14 | box-shadow: 0 1px 1px rgba(0, 0, 0, 0.12) !important; 15 | } 16 | .el-pagination { 17 | margin-top: 15px; 18 | } 19 | /* .el-cascader-menu { 20 | height: 300px; 21 | } */ 22 | .el-cascader-menu__wrap, 23 | .el-scrollbar__wrap { 24 | height: 290px !important; 25 | } 26 | .ql-editor { 27 | min-height: 500px; 28 | } 29 | -------------------------------------------------------------------------------- /src/assets/fonts/demo.css: -------------------------------------------------------------------------------- 1 | *{margin: 0;padding: 0;list-style: none;} 2 | /* 3 | KISSY CSS Reset 4 | 理念:1. reset 的目的不是清除浏览器的默认样式,这仅是部分工作。清除和重置是紧密不可分的。 5 | 2. reset 的目的不是让默认样式在所有浏览器下一致,而是减少默认样式有可能带来的问题。 6 | 3. reset 期望提供一套普适通用的基础样式。但没有银弹,推荐根据具体需求,裁剪和修改后再使用。 7 | 特色:1. 适应中文;2. 基于最新主流浏览器。 8 | 维护:玉伯, 正淳 9 | */ 10 | 11 | /** 清除内外边距 **/ 12 | body, h1, h2, h3, h4, h5, h6, hr, p, blockquote, /* structural elements 结构元素 */ 13 | dl, dt, dd, ul, ol, li, /* list elements 列表元素 */ 14 | pre, /* text formatting elements 文本格式元素 */ 15 | form, fieldset, legend, button, input, textarea, /* form elements 表单元素 */ 16 | th, td /* table elements 表格元素 */ { 17 | margin: 0; 18 | padding: 0; 19 | } 20 | 21 | /** 设置默认字体 **/ 22 | body, 23 | button, input, select, textarea /* for ie */ { 24 | font: 12px/1.5 tahoma, arial, \5b8b\4f53, sans-serif; 25 | } 26 | h1, h2, h3, h4, h5, h6 { font-size: 100%; } 27 | address, cite, dfn, em, var { font-style: normal; } /* 将斜体扶正 */ 28 | code, kbd, pre, samp { font-family: courier new, courier, monospace; } /* 统一等宽字体 */ 29 | small { font-size: 12px; } /* 小于 12px 的中文很难阅读,让 small 正常化 */ 30 | 31 | /** 重置列表元素 **/ 32 | ul, ol { list-style: none; } 33 | 34 | /** 重置文本格式元素 **/ 35 | a { text-decoration: none; } 36 | a:hover { text-decoration: underline; } 37 | 38 | 39 | /** 重置表单元素 **/ 40 | legend { color: #000; } /* for ie6 */ 41 | fieldset, img { border: 0; } /* img 搭车:让链接里的 img 无边框 */ 42 | button, input, select, textarea { font-size: 100%; } /* 使得表单元素在 ie 下能继承字体大小 */ 43 | /* 注:optgroup 无法扶正 */ 44 | 45 | /** 重置表格元素 **/ 46 | table { border-collapse: collapse; border-spacing: 0; } 47 | 48 | /* 清除浮动 */ 49 | .ks-clear:after, .clear:after { 50 | content: '\20'; 51 | display: block; 52 | height: 0; 53 | clear: both; 54 | } 55 | .ks-clear, .clear { 56 | *zoom: 1; 57 | } 58 | 59 | .main { 60 | padding: 30px 100px; 61 | width: 960px; 62 | margin: 0 auto; 63 | } 64 | .main h1{font-size:36px; color:#333; text-align:left;margin-bottom:30px; border-bottom: 1px solid #eee;} 65 | 66 | .helps{margin-top:40px;} 67 | .helps pre{ 68 | padding:20px; 69 | margin:10px 0; 70 | border:solid 1px #e7e1cd; 71 | background-color: #fffdef; 72 | overflow: auto; 73 | } 74 | 75 | .icon_lists{ 76 | width: 100% !important; 77 | 78 | } 79 | 80 | .icon_lists li{ 81 | float:left; 82 | width: 100px; 83 | height:180px; 84 | text-align: center; 85 | list-style: none !important; 86 | } 87 | .icon_lists .icon{ 88 | font-size: 42px; 89 | line-height: 100px; 90 | margin: 10px 0; 91 | color:#333; 92 | -webkit-transition: font-size 0.25s ease-out 0s; 93 | -moz-transition: font-size 0.25s ease-out 0s; 94 | transition: font-size 0.25s ease-out 0s; 95 | 96 | } 97 | .icon_lists .icon:hover{ 98 | font-size: 100px; 99 | } 100 | 101 | 102 | 103 | .markdown { 104 | color: #666; 105 | font-size: 14px; 106 | line-height: 1.8; 107 | } 108 | 109 | .highlight { 110 | line-height: 1.5; 111 | } 112 | 113 | .markdown img { 114 | vertical-align: middle; 115 | max-width: 100%; 116 | } 117 | 118 | .markdown h1 { 119 | color: #404040; 120 | font-weight: 500; 121 | line-height: 40px; 122 | margin-bottom: 24px; 123 | } 124 | 125 | .markdown h2, 126 | .markdown h3, 127 | .markdown h4, 128 | .markdown h5, 129 | .markdown h6 { 130 | color: #404040; 131 | margin: 1.6em 0 0.6em 0; 132 | font-weight: 500; 133 | clear: both; 134 | } 135 | 136 | .markdown h1 { 137 | font-size: 28px; 138 | } 139 | 140 | .markdown h2 { 141 | font-size: 22px; 142 | } 143 | 144 | .markdown h3 { 145 | font-size: 16px; 146 | } 147 | 148 | .markdown h4 { 149 | font-size: 14px; 150 | } 151 | 152 | .markdown h5 { 153 | font-size: 12px; 154 | } 155 | 156 | .markdown h6 { 157 | font-size: 12px; 158 | } 159 | 160 | .markdown hr { 161 | height: 1px; 162 | border: 0; 163 | background: #e9e9e9; 164 | margin: 16px 0; 165 | clear: both; 166 | } 167 | 168 | .markdown p, 169 | .markdown pre { 170 | margin: 1em 0; 171 | } 172 | 173 | .markdown > p, 174 | .markdown > blockquote, 175 | .markdown > .highlight, 176 | .markdown > ol, 177 | .markdown > ul { 178 | width: 80%; 179 | } 180 | 181 | .markdown ul > li { 182 | list-style: circle; 183 | } 184 | 185 | .markdown > ul li, 186 | .markdown blockquote ul > li { 187 | margin-left: 20px; 188 | padding-left: 4px; 189 | } 190 | 191 | .markdown > ul li p, 192 | .markdown > ol li p { 193 | margin: 0.6em 0; 194 | } 195 | 196 | .markdown ol > li { 197 | list-style: decimal; 198 | } 199 | 200 | .markdown > ol li, 201 | .markdown blockquote ol > li { 202 | margin-left: 20px; 203 | padding-left: 4px; 204 | } 205 | 206 | .markdown code { 207 | margin: 0 3px; 208 | padding: 0 5px; 209 | background: #eee; 210 | border-radius: 3px; 211 | } 212 | 213 | .markdown pre { 214 | border-radius: 6px; 215 | background: #f7f7f7; 216 | padding: 20px; 217 | } 218 | 219 | .markdown pre code { 220 | border: none; 221 | background: #f7f7f7; 222 | margin: 0; 223 | } 224 | 225 | .markdown strong, 226 | .markdown b { 227 | font-weight: 600; 228 | } 229 | 230 | .markdown > table { 231 | border-collapse: collapse; 232 | border-spacing: 0px; 233 | empty-cells: show; 234 | border: 1px solid #e9e9e9; 235 | width: 95%; 236 | margin-bottom: 24px; 237 | } 238 | 239 | .markdown > table th { 240 | white-space: nowrap; 241 | color: #333; 242 | font-weight: 600; 243 | 244 | } 245 | 246 | .markdown > table th, 247 | .markdown > table td { 248 | border: 1px solid #e9e9e9; 249 | padding: 8px 16px; 250 | text-align: left; 251 | } 252 | 253 | .markdown > table th { 254 | background: #F7F7F7; 255 | } 256 | 257 | .markdown blockquote { 258 | font-size: 90%; 259 | color: #999; 260 | border-left: 4px solid #e9e9e9; 261 | padding-left: 0.8em; 262 | margin: 1em 0; 263 | font-style: italic; 264 | } 265 | 266 | .markdown blockquote p { 267 | margin: 0; 268 | } 269 | 270 | .markdown .anchor { 271 | opacity: 0; 272 | transition: opacity 0.3s ease; 273 | margin-left: 8px; 274 | } 275 | 276 | .markdown .waiting { 277 | color: #ccc; 278 | } 279 | 280 | .markdown h1:hover .anchor, 281 | .markdown h2:hover .anchor, 282 | .markdown h3:hover .anchor, 283 | .markdown h4:hover .anchor, 284 | .markdown h5:hover .anchor, 285 | .markdown h6:hover .anchor { 286 | opacity: 1; 287 | display: inline-block; 288 | } 289 | 290 | .markdown > br, 291 | .markdown > p > br { 292 | clear: both; 293 | } 294 | 295 | 296 | .hljs { 297 | display: block; 298 | background: white; 299 | padding: 0.5em; 300 | color: #333333; 301 | overflow-x: auto; 302 | } 303 | 304 | .hljs-comment, 305 | .hljs-meta { 306 | color: #969896; 307 | } 308 | 309 | .hljs-string, 310 | .hljs-variable, 311 | .hljs-template-variable, 312 | .hljs-strong, 313 | .hljs-emphasis, 314 | .hljs-quote { 315 | color: #df5000; 316 | } 317 | 318 | .hljs-keyword, 319 | .hljs-selector-tag, 320 | .hljs-type { 321 | color: #a71d5d; 322 | } 323 | 324 | .hljs-literal, 325 | .hljs-symbol, 326 | .hljs-bullet, 327 | .hljs-attribute { 328 | color: #0086b3; 329 | } 330 | 331 | .hljs-section, 332 | .hljs-name { 333 | color: #63a35c; 334 | } 335 | 336 | .hljs-tag { 337 | color: #333333; 338 | } 339 | 340 | .hljs-title, 341 | .hljs-attr, 342 | .hljs-selector-id, 343 | .hljs-selector-class, 344 | .hljs-selector-attr, 345 | .hljs-selector-pseudo { 346 | color: #795da3; 347 | } 348 | 349 | .hljs-addition { 350 | color: #55a532; 351 | background-color: #eaffea; 352 | } 353 | 354 | .hljs-deletion { 355 | color: #bd2c00; 356 | background-color: #ffecec; 357 | } 358 | 359 | .hljs-link { 360 | text-decoration: underline; 361 | } 362 | 363 | pre{ 364 | background: #fff; 365 | } 366 | 367 | 368 | 369 | 370 | 371 | -------------------------------------------------------------------------------- /src/assets/fonts/demo_fontclass.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | IconFont 7 | 8 | 9 | 10 | 11 |
12 |

IconFont 图标

13 |
    14 | 15 |
  • 16 | 17 |
    show-password
    18 |
    .icon-showpassword
    19 |
  • 20 | 21 |
  • 22 | 23 |
    user
    24 |
    .icon-user
    25 |
  • 26 | 27 |
  • 28 | 29 |
    users
    30 |
    .icon-users
    31 |
  • 32 | 33 |
  • 34 | 35 |
    password-b
    36 |
    .icon-3702mima
    37 |
  • 38 | 39 |
  • 40 | 41 |
    06商品
    42 |
    .icon-shangpin
    43 |
  • 44 | 45 |
  • 46 | 47 |
    25单据
    48 |
    .icon-danju
    49 |
  • 50 | 51 |
  • 52 | 53 |
    28体积、空间
    54 |
    .icon-tijikongjian
    55 |
  • 56 | 57 |
  • 58 | 59 |
    225默认头像
    60 |
    .icon-morentouxiang
    61 |
  • 62 | 63 |
  • 64 | 65 |
    406报表
    66 |
    .icon-baobiao
    67 |
  • 68 | 69 |
  • 70 | 71 |
    lock_fill
    72 |
    .icon-lock_fill
    73 |
  • 74 | 75 |
76 | 77 |

font-class引用

78 |
79 | 80 |

font-class是unicode使用方式的一种变种,主要是解决unicode书写不直观,语意不明确的问题。

81 |

与unicode使用方式相比,具有如下特点:

82 |
    83 |
  • 兼容性良好,支持ie8+,及所有现代浏览器。
  • 84 |
  • 相比于unicode语意明确,书写更直观。可以很容易分辨这个icon是什么。
  • 85 |
  • 因为使用class来定义图标,所以当要替换图标时,只需要修改class里面的unicode引用。
  • 86 |
  • 不过因为本质上还是使用的字体,所以多色图标还是不支持的。
  • 87 |
88 |

使用步骤如下:

89 |

第一步:引入项目下面生成的fontclass代码:

90 | 91 | 92 |
<link rel="stylesheet" type="text/css" href="./iconfont.css">
93 |

第二步:挑选相应图标并获取类名,应用于页面:

94 |
<i class="iconfont icon-xxx"></i>
95 |
96 |

"iconfont"是你项目下的font-family。可以通过编辑项目查看,默认是"iconfont"。

97 |
98 |
99 | 100 | 101 | -------------------------------------------------------------------------------- /src/assets/fonts/demo_symbol.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | IconFont 7 | 8 | 9 | 10 | 24 | 25 | 26 |
27 |

IconFont 图标

28 |
    29 | 30 |
  • 31 | 34 |
    show-password
    35 |
    #icon-showpassword
    36 |
  • 37 | 38 |
  • 39 | 42 |
    user
    43 |
    #icon-user
    44 |
  • 45 | 46 |
  • 47 | 50 |
    users
    51 |
    #icon-users
    52 |
  • 53 | 54 |
  • 55 | 58 |
    password-b
    59 |
    #icon-3702mima
    60 |
  • 61 | 62 |
  • 63 | 66 |
    06商品
    67 |
    #icon-shangpin
    68 |
  • 69 | 70 |
  • 71 | 74 |
    25单据
    75 |
    #icon-danju
    76 |
  • 77 | 78 |
  • 79 | 82 |
    28体积、空间
    83 |
    #icon-tijikongjian
    84 |
  • 85 | 86 |
  • 87 | 90 |
    225默认头像
    91 |
    #icon-morentouxiang
    92 |
  • 93 | 94 |
  • 95 | 98 |
    406报表
    99 |
    #icon-baobiao
    100 |
  • 101 | 102 |
  • 103 | 106 |
    lock_fill
    107 |
    #icon-lock_fill
    108 |
  • 109 | 110 |
111 | 112 | 113 |

symbol引用

114 |
115 | 116 |

这是一种全新的使用方式,应该说这才是未来的主流,也是平台目前推荐的用法。相关介绍可以参考这篇文章 117 | 这种用法其实是做了一个svg的集合,与另外两种相比具有如下特点:

118 |
    119 |
  • 支持多色图标了,不再受单色限制。
  • 120 |
  • 通过一些技巧,支持像字体那样,通过font-size,color来调整样式。
  • 121 |
  • 兼容性较差,支持 ie9+,及现代浏览器。
  • 122 |
  • 浏览器渲染svg的性能一般,还不如png。
  • 123 |
124 |

使用步骤如下:

125 |

第一步:引入项目下面生成的symbol代码:

126 |
<script src="./iconfont.js"></script>
127 |

第二步:加入通用css代码(引入一次就行):

128 |
<style type="text/css">
129 | .icon {
130 |    width: 1em; height: 1em;
131 |    vertical-align: -0.15em;
132 |    fill: currentColor;
133 |    overflow: hidden;
134 | }
135 | </style>
136 |

第三步:挑选相应图标并获取类名,应用于页面:

137 |
<svg class="icon" aria-hidden="true">
138 |   <use xlink:href="#icon-xxx"></use>
139 | </svg>
140 |         
141 |
142 | 143 | 144 | -------------------------------------------------------------------------------- /src/assets/fonts/demo_unicode.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | IconFont 7 | 8 | 9 | 29 | 30 | 31 |
32 |

IconFont 图标

33 |
    34 | 35 |
  • 36 |  37 |
    show-password
    38 |
    &#xea3f;
    39 |
  • 40 | 41 |
  • 42 | 43 |
    user
    44 |
    &#xe89a;
    45 |
  • 46 | 47 |
  • 48 | 49 |
    users
    50 |
    &#xe8b5;
    51 |
  • 52 | 53 |
  • 54 | 55 |
    password-b
    56 |
    &#xe66c;
    57 |
  • 58 | 59 |
  • 60 | 61 |
    06商品
    62 |
    &#xe888;
    63 |
  • 64 | 65 |
  • 66 | 67 |
    25单据
    68 |
    &#xe89b;
    69 |
  • 70 | 71 |
  • 72 | 73 |
    28体积、空间
    74 |
    &#xe89f;
    75 |
  • 76 | 77 |
  • 78 | 79 |
    225默认头像
    80 |
    &#xe8c9;
    81 |
  • 82 | 83 |
  • 84 | 85 |
    406报表
    86 |
    &#xe902;
    87 |
  • 88 | 89 |
  • 90 | 91 |
    lock_fill
    92 |
    &#xe709;
    93 |
  • 94 | 95 |
96 |

unicode引用

97 |
98 | 99 |

unicode是字体在网页端最原始的应用方式,特点是:

100 |
    101 |
  • 兼容性最好,支持ie6+,及所有现代浏览器。
  • 102 |
  • 支持按字体的方式去动态调整图标大小,颜色等等。
  • 103 |
  • 但是因为是字体,所以不支持多色。只能使用平台里单色的图标,就算项目里有多色图标也会自动去色。
  • 104 |
105 |
106 |

注意:新版iconfont支持多色图标,这些多色图标在unicode模式下将不能使用,如果有需求建议使用symbol的引用方式

107 |
108 |

unicode使用步骤如下:

109 |

第一步:拷贝项目下面生成的font-face

110 |
@font-face {
111 |   font-family: 'iconfont';
112 |   src: url('iconfont.eot');
113 |   src: url('iconfont.eot?#iefix') format('embedded-opentype'),
114 |   url('iconfont.woff') format('woff'),
115 |   url('iconfont.ttf') format('truetype'),
116 |   url('iconfont.svg#iconfont') format('svg');
117 | }
118 | 
119 |

第二步:定义使用iconfont的样式

120 |
.iconfont{
121 |   font-family:"iconfont" !important;
122 |   font-size:16px;font-style:normal;
123 |   -webkit-font-smoothing: antialiased;
124 |   -webkit-text-stroke-width: 0.2px;
125 |   -moz-osx-font-smoothing: grayscale;
126 | }
127 | 
128 |

第三步:挑选相应图标并获取字体编码,应用于页面

129 |
<i class="iconfont">&#x33;</i>
130 | 131 |
132 |

"iconfont"是你项目下的font-family。可以通过编辑项目查看,默认是"iconfont"。

133 |
134 |
135 | 136 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /src/assets/fonts/iconfont.css: -------------------------------------------------------------------------------- 1 | 2 | @font-face {font-family: "iconfont"; 3 | src: url('iconfont.eot?t=1523541245904'); /* IE9*/ 4 | src: url('iconfont.eot?t=1523541245904#iefix') format('embedded-opentype'), /* IE6-IE8 */ 5 | url('data:application/x-font-woff;charset=utf-8;base64,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') format('woff'), 6 | url('iconfont.ttf?t=1523541245904') format('truetype'), /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ 7 | url('iconfont.svg?t=1523541245904#iconfont') format('svg'); /* iOS 4.1- */ 8 | } 9 | 10 | .iconfont { 11 | font-family:"iconfont" !important; 12 | font-size:16px; 13 | font-style:normal; 14 | -webkit-font-smoothing: antialiased; 15 | -moz-osx-font-smoothing: grayscale; 16 | } 17 | 18 | .icon-showpassword:before { content: "\ea3f"; } 19 | 20 | .icon-user:before { content: "\e89a"; } 21 | 22 | .icon-users:before { content: "\e8b5"; } 23 | 24 | .icon-3702mima:before { content: "\e66c"; } 25 | 26 | .icon-shangpin:before { content: "\e888"; } 27 | 28 | .icon-danju:before { content: "\e89b"; } 29 | 30 | .icon-tijikongjian:before { content: "\e89f"; } 31 | 32 | .icon-morentouxiang:before { content: "\e8c9"; } 33 | 34 | .icon-baobiao:before { content: "\e902"; } 35 | 36 | .icon-lock_fill:before { content: "\e709"; } 37 | 38 | -------------------------------------------------------------------------------- /src/assets/fonts/iconfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lysimportant/vue_shop/c9a9ca0b08cdf850b8fc1ee1b3732b13302f5007/src/assets/fonts/iconfont.eot -------------------------------------------------------------------------------- /src/assets/fonts/iconfont.js: -------------------------------------------------------------------------------- 1 | (function(window){var svgSprite='';var script=function(){var scripts=document.getElementsByTagName("script");return scripts[scripts.length-1]}();var shouldInjectCss=script.getAttribute("data-injectcss");var ready=function(fn){if(document.addEventListener){if(~["complete","loaded","interactive"].indexOf(document.readyState)){setTimeout(fn,0)}else{var loadFn=function(){document.removeEventListener("DOMContentLoaded",loadFn,false);fn()};document.addEventListener("DOMContentLoaded",loadFn,false)}}else if(document.attachEvent){IEContentLoaded(window,fn)}function IEContentLoaded(w,fn){var d=w.document,done=false,init=function(){if(!done){done=true;fn()}};var polling=function(){try{d.documentElement.doScroll("left")}catch(e){setTimeout(polling,50);return}init()};polling();d.onreadystatechange=function(){if(d.readyState=="complete"){d.onreadystatechange=null;init()}}}};var before=function(el,target){target.parentNode.insertBefore(el,target)};var prepend=function(el,target){if(target.firstChild){before(el,target.firstChild)}else{target.appendChild(el)}};function appendSvg(){var div,svg;div=document.createElement("div");div.innerHTML=svgSprite;svgSprite=null;svg=div.getElementsByTagName("svg")[0];if(svg){svg.setAttribute("aria-hidden","true");svg.style.position="absolute";svg.style.width=0;svg.style.height=0;svg.style.overflow="hidden";prepend(svg,document.body)}}if(shouldInjectCss&&!window.__iconfont__svg__cssinject__){window.__iconfont__svg__cssinject__=true;try{document.write("")}catch(e){console&&console.log(e)}}ready(appendSvg)})(window) -------------------------------------------------------------------------------- /src/assets/fonts/iconfont.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 7 | 8 | Created by iconfont 9 | 10 | 11 | 12 | 13 | 21 | 22 | 23 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/assets/fonts/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lysimportant/vue_shop/c9a9ca0b08cdf850b8fc1ee1b3732b13302f5007/src/assets/fonts/iconfont.ttf -------------------------------------------------------------------------------- /src/assets/fonts/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lysimportant/vue_shop/c9a9ca0b08cdf850b8fc1ee1b3732b13302f5007/src/assets/fonts/iconfont.woff -------------------------------------------------------------------------------- /src/assets/heima.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lysimportant/vue_shop/c9a9ca0b08cdf850b8fc1ee1b3732b13302f5007/src/assets/heima.png -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lysimportant/vue_shop/c9a9ca0b08cdf850b8fc1ee1b3732b13302f5007/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/manager.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lysimportant/vue_shop/c9a9ca0b08cdf850b8fc1ee1b3732b13302f5007/src/assets/manager.jpg -------------------------------------------------------------------------------- /src/common/mixin.js: -------------------------------------------------------------------------------- 1 | export const userAddFormRulesMixin = { 2 | data() { 3 | // 验证邮箱的规则 4 | var checkEmail = (rule, value, callback) => { 5 | const regEmail = /^\w+@\w+(\.\w+)+$/ // 验证邮箱的正则表达式 6 | if (regEmail.test(value)) { 7 | return callback() // 合法邮箱 8 | } 9 | // 返回一个错误提示 10 | callback(new Error('请输入合法的邮箱')) 11 | } 12 | // 验证手机的规则 13 | var checkMobeli = (rule, value, callback) => { 14 | const regMobile = /^1[34578]\d{9}$/ 15 | if (regMobile.test(value)) { 16 | return callback() 17 | } 18 | // 返回一个错误提示 19 | callback(new Error('请输入合法的手机号码')) 20 | } 21 | return { 22 | // 添加表单的验证规则对象 23 | addFormRules: { 24 | username: [ 25 | { required: true, message: '请输入登录名称', trigger: 'blur' }, 26 | { min: 3, max: 10, message: '长度在 3 到 10 个字符', trigger: 'blur' } 27 | ], 28 | password: [ 29 | { required: true, message: '请输入密码', trigger: 'blur' }, 30 | { 31 | min: 6, 32 | max: 15, 33 | message: '用户名长度在 6 到 15 个字符', 34 | trigger: 'blur' 35 | } 36 | ], 37 | email: [ 38 | { required: true, message: '请输入邮箱', trigger: 'blur' }, 39 | { validator: checkEmail, trigger: 'blur' } 40 | ], 41 | mobile: [ 42 | { required: true, message: '请输入手机', trigger: 'blur' }, 43 | { validator: checkMobeli, trigger: 'blur' } 44 | ] 45 | }, 46 | // 修改用户数据验证规则 47 | editFormRules: { 48 | email: [ 49 | { required: true, message: '请输入用户邮箱', trigger: 'blur' }, 50 | { validator: checkEmail, trigger: 'blur' } 51 | ], 52 | mobile: [ 53 | { required: true, message: '请输入用户手机', trigger: 'blur' }, 54 | { validator: checkMobeli, trigger: 'blur' } 55 | ] 56 | } 57 | } 58 | } 59 | } 60 | export const rolesFormRulesMixin = { 61 | data() { 62 | return { 63 | addFormRules: { 64 | roleName: [ 65 | { required: true, message: '请输入角色名字', trigger: 'blur' }, 66 | { 67 | min: 3, 68 | max: 10, 69 | message: '输入的范围是 3 ~ 10 为字符', 70 | triggetr: 'nlur' 71 | } 72 | ], 73 | roleDesc: [ 74 | { required: true, message: '请输入角色描述', trigger: 'blur' }, 75 | { 76 | min: 5, 77 | max: 20, 78 | message: '输入的范围是 5 ~ 20 为字符', 79 | triggetr: 'nlur' 80 | } 81 | ] 82 | }, 83 | editFormRules: { 84 | roleName: [ 85 | { required: true, message: '请输入角色名字', trigger: 'blur' }, 86 | { 87 | min: 3, 88 | max: 10, 89 | message: '输入的范围是 3 ~ 10 为字符', 90 | triggetr: 'nlur' 91 | } 92 | ], 93 | roleDesc: [ 94 | { required: true, message: '请输入角色描述', trigger: 'blur' }, 95 | { 96 | min: 5, 97 | max: 20, 98 | message: '输入的范围是 5 ~ 20 为字符', 99 | triggetr: 'nlur' 100 | } 101 | ] 102 | } 103 | } 104 | } 105 | } 106 | export const paramsFormRulesMixin = { 107 | data() { 108 | return { 109 | // 添加表单的验证规则 110 | addFormRules: { 111 | attr_name: [ 112 | { required: true, message: '请输入添加的分类', trigger: 'blur' }, 113 | { min: 2, max: 10, message: '长度在 2 到 10 个字符', trigger: 'blur' } 114 | ] 115 | }, 116 | // 修改表单的验证 117 | editFormRules: { 118 | attr_name: [ 119 | { required: true, message: '请输入修改的信息', trigger: 'blur' }, 120 | { min: 2, max: 10, message: '长度在 2 到 10 个字符', trigger: 'blur' } 121 | ] 122 | } 123 | } 124 | } 125 | } 126 | export const goodsAddFormRulesMixin = { 127 | data() { 128 | return { 129 | // 添加商品验证规则 130 | addFormRules: { 131 | goods_name: [ 132 | { required: true, message: '请输入商品的名称', trigger: 'blur' }, 133 | { 134 | min: 2, 135 | max: 30, 136 | message: '请输入 2 ~ 30 范围的字符', 137 | trigger: 'blur' 138 | } 139 | ], 140 | goods_price: [{ required: true, message: '请输入商品的价格', trigger: 'blur' }], 141 | goods_weight: [{ required: true, message: '请输入商品的重量', trigger: 'blur' }], 142 | goods_number: [{ required: true, message: '请输入商品的数量', trigger: 'blur' }], 143 | goods_cat: [{ required: true, message: '请选择商品分类', trigger: 'blur' }] 144 | } 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/common/utils.js: -------------------------------------------------------------------------------- 1 | /** 2 | * 格式化函数 , 给日期格式化 3 | * date为 new Date()对象, fmt为 'yyyy-MM-dd'的格式 4 | */ 5 | export function formatDate(date, fmt) { 6 | // 获取年份 7 | if (/(y+)/.test(fmt)) { 8 | let dateY = date.getFullYear() + ""; 9 | // RegExp.$1 在判断中出现过,且是括号括起来的,所以 RegExp.$1 就是 "yyyy" 10 | fmt = fmt.replace(RegExp.$1, dateY.substr(4 - RegExp.$1.length)); 11 | } 12 | 13 | //获取其他 14 | let o = { 15 | "M+": date.getMonth() + 1, 16 | "d+": date.getDate(), 17 | "h+": date.getHours(), 18 | "m+": date.getMinutes(), 19 | "s+": date.getSeconds() 20 | }; 21 | for (const k in o) { 22 | if (new RegExp(`(${k})`).test(fmt)) { 23 | let str = o[k] + ""; 24 | fmt = fmt.replace( 25 | RegExp.$1, 26 | RegExp.$1.length == 1 ? str : padLeftZero(str) 27 | ); 28 | } 29 | } 30 | return fmt; 31 | } 32 | function padLeftZero(str) { 33 | return ("00" + str).substr(str.length); 34 | } 35 | 36 | export function debounce(func, delay=50) { 37 | let timer = null 38 | return function (...args) { 39 | if(timer) clearTimeout(timer) 40 | timer = setTimeout(() => { 41 | func.apply(this, args) 42 | }, delay) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/common/webClick.js: -------------------------------------------------------------------------------- 1 | jQuery(document).ready(function($) { 2 | let Afont = 0 3 | $('body').click(function(e) { 4 | // const a = ['❤富强❤', '❤民主❤', '❤文明❤', '❤和谐❤', '❤自由❤', '❤平等❤', '公正', '法治', '爱国', '敬业', '诚信', '友善'] 5 | const language = ['❤富强❤', '❤民主❤', 'C++', 'Python', '❤文明❤', '❤和谐❤', 'PHP', 'Java', '❤和谐❤', '❤自由❤', '❤平等❤', 'HTML', 'CSS', 'JavaScript', 'C#', 'MySQL', '公正', '法治', '爱国', 'MongoDB', 'Linux', '敬业', '诚信', '友善'] 6 | const x = e.pageX 7 | const y = e.pageY 8 | const $i = $('').text(language[Afont]) 9 | Afont = (Afont + 1) % language.length 10 | $i.css({ 11 | 'z-index': 9999, 12 | top: y - 20, 13 | left: x, 14 | position: 'absolute', 15 | 'font-weight': 'bold', 16 | color: randomColor(), 17 | 'font-size': '20px' 18 | }) 19 | function randomColor() { 20 | return 'rgb(' + ~~(Math.random() * 255) + ',' + ~~(Math.random() * 255) + ',' + ~~(Math.random() * 255) + ')' 21 | } 22 | $('body').append($i) 23 | $i.animate( 24 | { 25 | top: y - 180, 26 | opacity: 0 27 | }, 28 | 1500, 29 | function() { 30 | $i.remove() 31 | } 32 | ) 33 | }) 34 | }) 35 | -------------------------------------------------------------------------------- /src/components/content/breadcrumb/Breadcrumb.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/components/home/Home.vue: -------------------------------------------------------------------------------- 1 | 56 | 57 | 122 | 123 | 180 | -------------------------------------------------------------------------------- /src/components/home/goods/cate/Cate.vue: -------------------------------------------------------------------------------- 1 | 84 | 85 | 290 | 291 | 299 | -------------------------------------------------------------------------------- /src/components/home/goods/list/List.vue: -------------------------------------------------------------------------------- 1 | 54 | 55 | 126 | 127 | 132 | -------------------------------------------------------------------------------- /src/components/home/goods/list/children/Add.vue: -------------------------------------------------------------------------------- 1 | 78 | 79 | 251 | 252 | 269 | -------------------------------------------------------------------------------- /src/components/home/goods/params/Params.vue: -------------------------------------------------------------------------------- 1 | 114 | 115 | 343 | 344 | 365 | -------------------------------------------------------------------------------- /src/components/home/order/Order.vue: -------------------------------------------------------------------------------- 1 | 83 | 84 | 229 | 230 | 238 | -------------------------------------------------------------------------------- /src/components/home/power/rights/Rights.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /src/components/home/power/roles/Roles.vue: -------------------------------------------------------------------------------- 1 | 103 | 104 | 287 | 288 | 307 | -------------------------------------------------------------------------------- /src/components/home/report/Report.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/components/home/users/Users.vue: -------------------------------------------------------------------------------- 1 | 116 | 117 | 314 | 315 | 320 | -------------------------------------------------------------------------------- /src/components/home/welcome/Welcome.vue: -------------------------------------------------------------------------------- 1 | 60 | 61 | 66 | 67 | 106 | -------------------------------------------------------------------------------- /src/components/login/Login.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 83 | 84 | 129 | -------------------------------------------------------------------------------- /src/main-dev.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import './plugins/element.js' 5 | import TreeTable from 'vue-table-with-tree-grid' 6 | import document from '@/common/webClick' 7 | // 导入字体图标 8 | import './assets/fonts/iconfont.css' 9 | // 导入全局样式表 10 | import './assets/css/global.css' 11 | // 导入富文本编辑器 12 | 13 | import VueQuillEditor from 'vue-quill-editor' 14 | 15 | import 'quill/dist/quill.core.css' // import styles 16 | import 'quill/dist/quill.snow.css' // for snow theme 17 | import 'quill/dist/quill.bubble.css' // for bubble theme 18 | // 导入NProgress 对应的js和css 19 | import NProgress from 'nprogress' 20 | import 'nprogress/nprogress.css' 21 | import axios from 'axios' 22 | // 在request拦截器中展示进度条 NProgress.start() 23 | // axios.defaults.baseURL = 'http://127.0.0.1:8888/api/private/v1/' 24 | axios.defaults.baseURL = 'https://lianghj.top:8888/api/private/v1/' 25 | // axios.defaults.baseURL = 'https://www.liulongbin.top:8888/api/private/v1/' 26 | axios.interceptors.request.use(config => { 27 | NProgress.start() 28 | // 登录授权 请求验证是否有token 需要授权的 API ,必须在请求头中使用 `Authorization` 字段提供 `token` 令牌 29 | config.headers.Authorization = window.sessionStorage.getItem('token') 30 | return config // 必须返回否则没有值 31 | }) 32 | // 在reponse拦截器中,隐藏进度条 NProgress.done() 33 | axios.interceptors.response.use(config => { 34 | NProgress.done() 35 | return config 36 | }) 37 | Vue.prototype.$http = axios 38 | 39 | Vue.config.productionTip = false 40 | Vue.component('tree-table', TreeTable) 41 | // 将富文本编辑器注册为全局组件 42 | Vue.use(VueQuillEditor) 43 | // 全局时间过滤器 44 | Vue.filter('dataFormat', function (originVal) { 45 | const dt = new Date(originVal) 46 | 47 | const y = dt.getFullYear() 48 | const m = (dt.getMonth() + 1 + '').padStart(2, '0') 49 | const d = (dt.getDate() + '').padStart(2, '0') 50 | 51 | const hh = (dt.getHours() + '').padStart(2, '0') 52 | const mm = (dt.getMinutes() + '').padStart(2, '0') 53 | const ss = (dt.getSeconds() + '').padStart(2, '0') 54 | // yyyy-mm-dd hh:mm:ss 55 | return `${y}-${m}-${d} ${hh}:${mm}:${ss}` 56 | }) 57 | new Vue({ 58 | router, 59 | render: h => h(App) 60 | }).$mount('#app') 61 | -------------------------------------------------------------------------------- /src/main-prod.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | // import './plugins/element.js' 5 | import document from '@/common/webClick' 6 | 7 | import TreeTable from 'vue-table-with-tree-grid' 8 | 9 | // 导入字体图标 10 | import './assets/fonts/iconfont.css' 11 | // 导入全局样式表 12 | import './assets/css/global.css' 13 | 14 | // 导入富文本编辑器 15 | import VueQuillEditor from 'vue-quill-editor' 16 | 17 | // 导入NProgress 对应的js和css 18 | import NProgress from 'nprogress' 19 | 20 | import axios from 'axios' 21 | // 在request拦截器中展示进度条 NProgress.start() 22 | axios.defaults.baseURL = 'https://lianghj.top:8888/api/private/v1/' 23 | // axios.defaults.baseURL = 'https://www.liulongbin.top:8888/api/private/v1/' 24 | axios.interceptors.request.use(config => { 25 | NProgress.start() 26 | // 登录授权 请求验证是否有token 需要授权的 API ,必须在请求头中使用 `Authorization` 字段提供 `token` 令牌 27 | config.headers.Authorization = window.sessionStorage.getItem('token') 28 | return config // 必须返回否则没有值 29 | }) 30 | // 在reponse拦截器中,隐藏进度条 NProgress.done() 31 | axios.interceptors.response.use(config => { 32 | NProgress.done() 33 | return config 34 | }) 35 | Vue.prototype.$http = axios 36 | 37 | Vue.config.productionTip = false 38 | Vue.component('tree-table', TreeTable) 39 | // 将富文本编辑器注册为全局组件 40 | Vue.use(VueQuillEditor) 41 | // 全局时间过滤器 42 | Vue.filter('dataFormat', function (originVal) { 43 | const dt = new Date(originVal) 44 | 45 | const y = dt.getFullYear() 46 | const m = (dt.getMonth() + 1 + '').padStart(2, '0') 47 | const d = (dt.getDate() + '').padStart(2, '0') 48 | 49 | const hh = (dt.getHours() + '').padStart(2, '0') 50 | const mm = (dt.getMinutes() + '').padStart(2, '0') 51 | const ss = (dt.getSeconds() + '').padStart(2, '0') 52 | // yyyy-mm-dd hh:mm:ss 53 | return `${y}-${m}-${d} ${hh}:${mm}:${ss}` 54 | }) 55 | new Vue({ 56 | router, 57 | render: h => h(App) 58 | }).$mount('#app') 59 | -------------------------------------------------------------------------------- /src/plugins/element.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | // 引入弹框提示组件 Message 需要全局引用 使用 Vue.prototype 3 | import { 4 | Button, 5 | Form, 6 | FormItem, 7 | Input, 8 | Message, 9 | Container, 10 | Header, 11 | Aside, 12 | Main, 13 | Menu, 14 | Submenu, 15 | MenuItem, 16 | Breadcrumb, 17 | BreadcrumbItem, 18 | Card, 19 | Row, 20 | Col, 21 | Table, 22 | TableColumn, 23 | Switch, 24 | Tooltip, 25 | Pagination, 26 | Dialog, 27 | MessageBox, 28 | Tag, 29 | Tree, 30 | Select, 31 | Option, 32 | Cascader, 33 | Alert, 34 | Tabs, 35 | TabPane, 36 | Steps, 37 | Step, 38 | CheckboxGroup, 39 | Checkbox, 40 | Upload, 41 | Timeline, 42 | TimelineItem 43 | } from 'element-ui' 44 | 45 | Vue.use(Button) 46 | Vue.use(Form) 47 | Vue.use(FormItem) 48 | Vue.use(Input) 49 | Vue.use(Container) 50 | Vue.use(Input) 51 | Vue.use(Header) 52 | Vue.use(Aside) 53 | Vue.use(Main) 54 | Vue.use(Menu) 55 | Vue.use(MenuItem) 56 | Vue.use(Submenu) 57 | Vue.use(Breadcrumb) 58 | Vue.use(BreadcrumbItem) 59 | Vue.use(Card) 60 | Vue.use(Row) 61 | Vue.use(Col) 62 | Vue.use(Table) 63 | Vue.use(TableColumn) 64 | Vue.use(Switch) 65 | Vue.use(Tooltip) 66 | Vue.use(Pagination) 67 | Vue.use(Dialog) 68 | Vue.use(Tag) 69 | Vue.use(Tree) 70 | Vue.use(Select) 71 | Vue.use(Option) 72 | Vue.use(Cascader) 73 | Vue.use(Alert) 74 | Vue.use(Tabs) 75 | Vue.use(TabPane) 76 | Vue.use(Steps) 77 | Vue.use(Step) 78 | Vue.use(Checkbox) 79 | Vue.use(CheckboxGroup) 80 | Vue.use(Upload) 81 | Vue.use(Timeline) 82 | Vue.use(TimelineItem) 83 | Vue.prototype.$message = Message 84 | Vue.prototype.$confirm = MessageBox.confirm 85 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | const Login = () => import(/* webpackChunkName: "login_home_welome" */ 'components/login/Login') 4 | const Home = () => import(/* webpackChunkName: "login_home_welome" */ 'components/home/Home') 5 | const Welcome = () => import(/* webpackChunkName: "login_home_welome" */ 'components/home/welcome/Welcome') 6 | 7 | const Users = () => import(/* webpackChunkName: "Users_Rights_Roles" */ 'components/home/users/Users') 8 | const Rights = () => import(/* webpackChunkName: "Users_Rights_Roles" */ 'components/home/power/rights/Rights') 9 | const Roles = () => import(/* webpackChunkName: "Users_Rights_Roles" */ 'components/home/power/roles/Roles') 10 | 11 | const Cate = () => import(/* webpackChunkName: "Cate_Params" */ 'components/home/goods/cate/Cate') 12 | const Params = () => import(/* webpackChunkName: "Cate_Params" */ 'components/home/goods/params/Params') 13 | 14 | const GoodsList = () => import(/* webpackChunkName: "GoodsList_Add" */ 'components/home/goods/list/List') 15 | const Add = () => import(/* webpackChunkName: "GoodsList_Add" */ 'components/home/goods/list/children/Add') 16 | 17 | const Order = () => import(/* webpackChunkName: "Order_Report" */ 'components/home/order/Order') 18 | const Report = () => import(/* webpackChunkName: "Order_Report" */ 'components/home/report/Report') 19 | Vue.use(VueRouter) 20 | 21 | const routes = [ 22 | { 23 | path: '/', 24 | redirect: '/login' 25 | }, 26 | { 27 | path: '/login', 28 | component: Login 29 | }, 30 | { 31 | path: '/home', 32 | component: Home, 33 | redirect: '/welcome', 34 | children: [ 35 | { 36 | path: '/welcome', 37 | component: Welcome 38 | }, 39 | { 40 | path: '/users', 41 | component: Users 42 | }, 43 | { 44 | path: '/rights', 45 | component: Rights 46 | }, 47 | { 48 | path: '/roles', 49 | component: Roles 50 | }, 51 | { 52 | path: '/categories', 53 | component: Cate 54 | }, 55 | { 56 | path: '/params', 57 | component: Params 58 | }, 59 | { 60 | path: '/goods', 61 | component: GoodsList 62 | }, 63 | { 64 | path: '/goods/add', 65 | component: Add 66 | }, 67 | { 68 | path: '/orders', 69 | component: Order 70 | }, 71 | { 72 | path: '/reports', 73 | component: Report 74 | } 75 | ] 76 | } 77 | ] 78 | const router = new VueRouter({ 79 | mode: 'history', 80 | routes 81 | }) 82 | 83 | router.beforeEach((to, from, next) => { 84 | // to 将访问哪一个路径 85 | // from 代表从哪个路径跳转而来 86 | // next 是一个函数,表示放行 87 | // next() 放行 next('/login') 强制跳转 88 | if (to.path === '/login') return next() 89 | // 获取token 90 | const token = window.sessionStorage.getItem('token') 91 | if (!token) return next('/login') 92 | next() 93 | }) 94 | 95 | export default router 96 | -------------------------------------------------------------------------------- /vue.config.js: -------------------------------------------------------------------------------- 1 | const { tap } = require("lodash") 2 | 3 | module.exports = { 4 | configureWebpack: { 5 | resolve: { 6 | alias: { 7 | "assets": '@/assets', 8 | "common": '@/common', 9 | "components": '@/components', 10 | "views": '@/views', 11 | "network": '@/network', 12 | } 13 | } 14 | }, 15 | // 发布模式 16 | chainWebpack: config => { 17 | config.when(process.env.NODE_ENV === 'production', config => { 18 | config.entry('app').clear().add('./src/main-prod.js') 19 | config.set('externals', { 20 | vue: 'Vue', 21 | 'vue-router': 'VueRouter', 22 | axios: 'axios', 23 | lodash: '_', 24 | echarts: 'echarts', 25 | nprogress: 'NProgress', 26 | 'vue-quill-editor': 'VueQuillEditor', 27 | jquery: '$' 28 | }) 29 | config.plugin('html').tap(args => { 30 | args[0].isProd = true 31 | return args 32 | }) 33 | }) 34 | 35 | // 开发模式 36 | config.when(process.env.NODE_ENV === 'development', config => { 37 | config.entry('app').clear().add('./src/main-dev.js') 38 | config.plugin('html').tap(args => { 39 | args[0].isProd = false 40 | return args 41 | }) 42 | }) 43 | } 44 | } 45 | --------------------------------------------------------------------------------