1.2.3 后台操作按钮调整及其新增开启拼团功能
17
.babelrc
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"presets": [
|
||||
["env", {
|
||||
"modules": false,
|
||||
"targets": {
|
||||
"browsers": ["> 1%", "last 2 versions", "not ie <= 8"]
|
||||
}
|
||||
}],
|
||||
"stage-2"
|
||||
],
|
||||
"plugins":["transform-vue-jsx", "transform-runtime"],
|
||||
"env": {
|
||||
"development":{
|
||||
"plugins": ["dynamic-import-node"]
|
||||
}
|
||||
}
|
||||
}
|
14
.editorconfig
Normal file
@ -0,0 +1,14 @@
|
||||
# http://editorconfig.org
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
insert_final_newline = false
|
||||
trim_trailing_whitespace = false
|
3
.eslintignore
Normal file
@ -0,0 +1,3 @@
|
||||
build/*.js
|
||||
config/*.js
|
||||
src/assets
|
196
.eslintrc.js
Normal file
@ -0,0 +1,196 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
parserOptions: {
|
||||
parser: 'babel-eslint',
|
||||
sourceType: 'module'
|
||||
},
|
||||
env: {
|
||||
browser: true,
|
||||
node: true,
|
||||
es6: true,
|
||||
},
|
||||
extends: ['plugin:vue/recommended', 'eslint:recommended'],
|
||||
|
||||
// add your custom rules here
|
||||
//it is base on https://github.com/vuejs/eslint-config-vue
|
||||
rules: {
|
||||
"vue/max-attributes-per-line": [2, {
|
||||
"singleline": 10,
|
||||
"multiline": {
|
||||
"max": 1,
|
||||
"allowFirstLine": false
|
||||
}
|
||||
}],
|
||||
"vue/name-property-casing": ["error", "PascalCase"],
|
||||
'accessor-pairs': 2,
|
||||
'arrow-spacing': [2, {
|
||||
'before': true,
|
||||
'after': true
|
||||
}],
|
||||
'block-spacing': [2, 'always'],
|
||||
'brace-style': [2, '1tbs', {
|
||||
'allowSingleLine': true
|
||||
}],
|
||||
'camelcase': [0, {
|
||||
'properties': 'always'
|
||||
}],
|
||||
'comma-dangle': [2, 'never'],
|
||||
'comma-spacing': [2, {
|
||||
'before': false,
|
||||
'after': true
|
||||
}],
|
||||
'comma-style': [2, 'last'],
|
||||
'constructor-super': 2,
|
||||
'curly': [2, 'multi-line'],
|
||||
'dot-location': [2, 'property'],
|
||||
'eol-last': 2,
|
||||
'eqeqeq': [2, 'allow-null'],
|
||||
'generator-star-spacing': [2, {
|
||||
'before': true,
|
||||
'after': true
|
||||
}],
|
||||
'handle-callback-err': [2, '^(err|error)$'],
|
||||
'indent': [2, 2, {
|
||||
'SwitchCase': 1
|
||||
}],
|
||||
'jsx-quotes': [2, 'prefer-single'],
|
||||
'key-spacing': [2, {
|
||||
'beforeColon': false,
|
||||
'afterColon': true
|
||||
}],
|
||||
'keyword-spacing': [2, {
|
||||
'before': true,
|
||||
'after': true
|
||||
}],
|
||||
'new-cap': [2, {
|
||||
'newIsCap': true,
|
||||
'capIsNew': false
|
||||
}],
|
||||
'new-parens': 2,
|
||||
'no-array-constructor': 2,
|
||||
'no-caller': 2,
|
||||
'no-console': 'off',
|
||||
'no-class-assign': 2,
|
||||
'no-cond-assign': 2,
|
||||
'no-const-assign': 2,
|
||||
'no-control-regex': 2,
|
||||
'no-delete-var': 2,
|
||||
'no-dupe-args': 2,
|
||||
'no-dupe-class-members': 2,
|
||||
'no-dupe-keys': 2,
|
||||
'no-duplicate-case': 2,
|
||||
'no-empty-character-class': 2,
|
||||
'no-empty-pattern': 2,
|
||||
'no-eval': 2,
|
||||
'no-ex-assign': 2,
|
||||
'no-extend-native': 2,
|
||||
'no-extra-bind': 2,
|
||||
'no-extra-boolean-cast': 2,
|
||||
'no-extra-parens': [2, 'functions'],
|
||||
'no-fallthrough': 2,
|
||||
'no-floating-decimal': 2,
|
||||
'no-func-assign': 2,
|
||||
'no-implied-eval': 2,
|
||||
'no-inner-declarations': [2, 'functions'],
|
||||
'no-invalid-regexp': 2,
|
||||
'no-irregular-whitespace': 2,
|
||||
'no-iterator': 2,
|
||||
'no-label-var': 2,
|
||||
'no-labels': [2, {
|
||||
'allowLoop': false,
|
||||
'allowSwitch': false
|
||||
}],
|
||||
'no-lone-blocks': 2,
|
||||
'no-mixed-spaces-and-tabs': 2,
|
||||
'no-multi-spaces': 2,
|
||||
'no-multi-str': 2,
|
||||
'no-multiple-empty-lines': [2, {
|
||||
'max': 1
|
||||
}],
|
||||
'no-native-reassign': 2,
|
||||
'no-negated-in-lhs': 2,
|
||||
'no-new-object': 2,
|
||||
'no-new-require': 2,
|
||||
'no-new-symbol': 2,
|
||||
'no-new-wrappers': 2,
|
||||
'no-obj-calls': 2,
|
||||
'no-octal': 2,
|
||||
'no-octal-escape': 2,
|
||||
'no-path-concat': 2,
|
||||
'no-proto': 2,
|
||||
'no-redeclare': 2,
|
||||
'no-regex-spaces': 2,
|
||||
'no-return-assign': [2, 'except-parens'],
|
||||
'no-self-assign': 2,
|
||||
'no-self-compare': 2,
|
||||
'no-sequences': 2,
|
||||
'no-shadow-restricted-names': 2,
|
||||
'no-spaced-func': 2,
|
||||
'no-sparse-arrays': 2,
|
||||
'no-this-before-super': 2,
|
||||
'no-throw-literal': 2,
|
||||
'no-trailing-spaces': 2,
|
||||
'no-undef': 2,
|
||||
'no-undef-init': 2,
|
||||
'no-unexpected-multiline': 2,
|
||||
'no-unmodified-loop-condition': 2,
|
||||
'no-unneeded-ternary': [2, {
|
||||
'defaultAssignment': false
|
||||
}],
|
||||
'no-unreachable': 2,
|
||||
'no-unsafe-finally': 2,
|
||||
'no-unused-vars': [2, {
|
||||
'vars': 'all',
|
||||
'args': 'none'
|
||||
}],
|
||||
'no-useless-call': 2,
|
||||
'no-useless-computed-key': 2,
|
||||
'no-useless-constructor': 2,
|
||||
'no-useless-escape': 0,
|
||||
'no-whitespace-before-property': 2,
|
||||
'no-with': 2,
|
||||
'one-var': [2, {
|
||||
'initialized': 'never'
|
||||
}],
|
||||
'operator-linebreak': [2, 'after', {
|
||||
'overrides': {
|
||||
'?': 'before',
|
||||
':': 'before'
|
||||
}
|
||||
}],
|
||||
'padded-blocks': [2, 'never'],
|
||||
'quotes': [2, 'single', {
|
||||
'avoidEscape': true,
|
||||
'allowTemplateLiterals': true
|
||||
}],
|
||||
'semi': [2, 'never'],
|
||||
'semi-spacing': [2, {
|
||||
'before': false,
|
||||
'after': true
|
||||
}],
|
||||
'space-before-blocks': [2, 'always'],
|
||||
'space-before-function-paren': [2, 'never'],
|
||||
'space-in-parens': [2, 'never'],
|
||||
'space-infix-ops': 2,
|
||||
'space-unary-ops': [2, {
|
||||
'words': true,
|
||||
'nonwords': false
|
||||
}],
|
||||
'spaced-comment': [2, 'always', {
|
||||
'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
|
||||
}],
|
||||
'template-curly-spacing': [2, 'never'],
|
||||
'use-isnan': 2,
|
||||
'valid-typeof': 2,
|
||||
'wrap-iife': [2, 'any'],
|
||||
'yield-star-spacing': [2, 'both'],
|
||||
'yoda': [2, 'never'],
|
||||
'prefer-const': 2,
|
||||
'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
|
||||
'object-curly-spacing': [2, 'always', {
|
||||
objectsInObjects: false
|
||||
}],
|
||||
'array-bracket-spacing': [2, 'never']
|
||||
}
|
||||
}
|
||||
|
16
.gitignore
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
.DS_Store
|
||||
node_modules/
|
||||
dist/
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
|
||||
# Editor directories and files
|
||||
.idea
|
||||
.vscode
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
10
.postcssrc.js
Normal file
@ -0,0 +1,10 @@
|
||||
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||
|
||||
module.exports = {
|
||||
"plugins": {
|
||||
"postcss-import": {},
|
||||
"postcss-url": {},
|
||||
// to edit target browsers: use "browserslist" field in package.json
|
||||
"autoprefixer": {}
|
||||
}
|
||||
}
|
5
.travis.yml
Normal file
@ -0,0 +1,5 @@
|
||||
language: node_js
|
||||
node_js: stable
|
||||
script: npm run test
|
||||
notifications:
|
||||
email: false
|
191
LICENSE
Normal file
@ -0,0 +1,191 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction, and
|
||||
distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by the copyright
|
||||
owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all other entities
|
||||
that control, are controlled by, or are under common control with that entity.
|
||||
For the purposes of this definition, "control" means (i) the power, direct or
|
||||
indirect, to cause the direction or management of such entity, whether by
|
||||
contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity exercising
|
||||
permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications, including
|
||||
but not limited to software source code, documentation source, and configuration
|
||||
files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical transformation or
|
||||
translation of a Source form, including but not limited to compiled object code,
|
||||
generated documentation, and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or Object form, made
|
||||
available under the License, as indicated by a copyright notice that is included
|
||||
in or attached to the work (an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object form, that
|
||||
is based on (or derived from) the Work and for which the editorial revisions,
|
||||
annotations, elaborations, or other modifications represent, as a whole, an
|
||||
original work of authorship. For the purposes of this License, Derivative Works
|
||||
shall not include works that remain separable from, or merely link (or bind by
|
||||
name) to the interfaces of, the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including the original version
|
||||
of the Work and any modifications or additions to that Work or Derivative Works
|
||||
thereof, that is intentionally submitted to Licensor for inclusion in the Work
|
||||
by the copyright owner or by an individual or Legal Entity authorized to submit
|
||||
on behalf of the copyright owner. For the purposes of this definition,
|
||||
"submitted" means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems, and
|
||||
issue tracking systems that are managed by, or on behalf of, the Licensor for
|
||||
the purpose of discussing and improving the Work, but excluding communication
|
||||
that is conspicuously marked or otherwise designated in writing by the copyright
|
||||
owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf
|
||||
of whom a Contribution has been received by Licensor and subsequently
|
||||
incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License.
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the Work and such
|
||||
Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License.
|
||||
|
||||
Subject to the terms and conditions of this License, each Contributor hereby
|
||||
grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free,
|
||||
irrevocable (except as stated in this section) patent license to make, have
|
||||
made, use, offer to sell, sell, import, and otherwise transfer the Work, where
|
||||
such license applies only to those patent claims licensable by such Contributor
|
||||
that are necessarily infringed by their Contribution(s) alone or by combination
|
||||
of their Contribution(s) with the Work to which such Contribution(s) was
|
||||
submitted. If You institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work or a
|
||||
Contribution incorporated within the Work constitutes direct or contributory
|
||||
patent infringement, then any patent licenses granted to You under this License
|
||||
for that Work shall terminate as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution.
|
||||
|
||||
You may reproduce and distribute copies of the Work or Derivative Works thereof
|
||||
in any medium, with or without modifications, and in Source or Object form,
|
||||
provided that You meet the following conditions:
|
||||
|
||||
You must give any other recipients of the Work or Derivative Works a copy of
|
||||
this License; and
|
||||
You must cause any modified files to carry prominent notices stating that You
|
||||
changed the files; and
|
||||
You must retain, in the Source form of any Derivative Works that You distribute,
|
||||
all copyright, patent, trademark, and attribution notices from the Source form
|
||||
of the Work, excluding those notices that do not pertain to any part of the
|
||||
Derivative Works; and
|
||||
If the Work includes a "NOTICE" text file as part of its distribution, then any
|
||||
Derivative Works that You distribute must include a readable copy of the
|
||||
attribution notices contained within such NOTICE file, excluding those notices
|
||||
that do not pertain to any part of the Derivative Works, in at least one of the
|
||||
following places: within a NOTICE text file distributed as part of the
|
||||
Derivative Works; within the Source form or documentation, if provided along
|
||||
with the Derivative Works; or, within a display generated by the Derivative
|
||||
Works, if and wherever such third-party notices normally appear. The contents of
|
||||
the NOTICE file are for informational purposes only and do not modify the
|
||||
License. You may add Your own attribution notices within Derivative Works that
|
||||
You distribute, alongside or as an addendum to the NOTICE text from the Work,
|
||||
provided that such additional attribution notices cannot be construed as
|
||||
modifying the License.
|
||||
You may add Your own copyright statement to Your modifications and may provide
|
||||
additional or different license terms and conditions for use, reproduction, or
|
||||
distribution of Your modifications, or for any such Derivative Works as a whole,
|
||||
provided Your use, reproduction, and distribution of the Work otherwise complies
|
||||
with the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions.
|
||||
|
||||
Unless You explicitly state otherwise, any Contribution intentionally submitted
|
||||
for inclusion in the Work by You to the Licensor shall be under the terms and
|
||||
conditions of this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify the terms of
|
||||
any separate license agreement you may have executed with Licensor regarding
|
||||
such Contributions.
|
||||
|
||||
6. Trademarks.
|
||||
|
||||
This License does not grant permission to use the trade names, trademarks,
|
||||
service marks, or product names of the Licensor, except as required for
|
||||
reasonable and customary use in describing the origin of the Work and
|
||||
reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, Licensor provides the
|
||||
Work (and each Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied,
|
||||
including, without limitation, any warranties or conditions of TITLE,
|
||||
NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are
|
||||
solely responsible for determining the appropriateness of using or
|
||||
redistributing the Work and assume any risks associated with Your exercise of
|
||||
permissions under this License.
|
||||
|
||||
8. Limitation of Liability.
|
||||
|
||||
In no event and under no legal theory, whether in tort (including negligence),
|
||||
contract, or otherwise, unless required by applicable law (such as deliberate
|
||||
and grossly negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special, incidental,
|
||||
or consequential damages of any character arising as a result of this License or
|
||||
out of the use or inability to use the Work (including but not limited to
|
||||
damages for loss of goodwill, work stoppage, computer failure or malfunction, or
|
||||
any and all other commercial damages or losses), even if such Contributor has
|
||||
been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability.
|
||||
|
||||
While redistributing the Work or Derivative Works thereof, You may choose to
|
||||
offer, and charge a fee for, acceptance of support, warranty, indemnity, or
|
||||
other liability obligations and/or rights consistent with this License. However,
|
||||
in accepting such obligations, You may act only on Your own behalf and on Your
|
||||
sole responsibility, not on behalf of any other Contributor, and only if You
|
||||
agree to indemnify, defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason of your
|
||||
accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work
|
||||
|
||||
To apply the Apache License to your work, attach the following boilerplate
|
||||
notice, with the fields enclosed by brackets "{}" replaced with your own
|
||||
identifying information. (Don't include the brackets!) The text should be
|
||||
enclosed in the appropriate comment syntax for the file format. We also
|
||||
recommend that a file or class name and description of purpose be included on
|
||||
the same "printed page" as the copyright notice for easier identification within
|
||||
third-party archives.
|
||||
|
||||
Copyright 2018 Elune
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
145
README.md
Normal file
@ -0,0 +1,145 @@
|
||||
<h1 style="text-align: center">yshop意象商城系统</h1>
|
||||
|
||||
|
||||
#### 项目简介
|
||||
yshop基于当前流行技术组合: SpringBoot2+Jpa+MybatisPlus+SpringSecurity+jwt+redis+Vue的前后端分离的商城系统, 包含商城、拼团、砍价、
|
||||
秒杀、优惠券、积分、分销等功能,更适合企业或个人二次开发;
|
||||
|
||||
**开发文档** 【[查看文档](https://gitee.com/guchengwuyue/yshopmall/wikis/%E5%BC%80%E5%8F%91%E7%8E%AF%E5%A2%83?sort_id=1718722)】
|
||||
|
||||
#### 体验地址
|
||||
|
||||
| | 后台系统 | 前端(公众号) |
|
||||
|--- |--- | --- |
|
||||
| | https://yshop.dayouqiantu.cn |g公众号:YshopMall |
|
||||
| | 后台体验账号/密码:admin/123456 | 公众号: |
|
||||
|
||||
|
||||
#### 项目源码
|
||||
|
||||
| | 后台系统源码 | 后台系统前端源码 |
|
||||
|--- |--- | --- |
|
||||
| 码云 | https://gitee.com/guchengwuyue/yshopmall | https://gitee.com/guchengwuyue/yshopmall_qd |
|
||||
| github | https://github.com/guchengwuyue/yshopmall |https://github.com/guchengwuyue/yshopmall_qd |
|
||||
|
||||
#### 开源版本与VIP版本说明
|
||||
|
||||
|
||||
### 开源版
|
||||
1.包括整个商城系统后台、数据库、api(只是简单的配置好模块);
|
||||
|
||||
2.本版本本身属于独立后台商城管理系统、可独立作为cms、商城等等后台使用;
|
||||
|
||||
3.可以个人、企业直接使用。
|
||||
|
||||
### VIP版
|
||||
1.包括整个商城系统后台、数据库、API、H5;
|
||||
|
||||
2.本版本是演示的所有功能代码;
|
||||
|
||||
3.加入VIP、享有后续所有功能免费升级及其技术支持等。
|
||||
|
||||
4、VIP为终身,【[详情请查看](https://gitee.com/guchengwuyue/yshopmall/wikis/pages?sort_id=1715823&doc_id=441578)】
|
||||
|
||||
|
||||
## 商城功能
|
||||
|
||||
* 一:商品模块:商品添加、规格设置,商品上下架等
|
||||
* 二:订单模块:下单、购物车、支付,发货、收货、评价、退款等
|
||||
* 三:营销模块:积分、优惠券、分销、砍价、拼团、秒杀(、到店核销等
|
||||
* 四:微信模块:自定义菜单、自动回复、微信授权、图文管理、模板消息推送
|
||||
* 五:配置模块:各种配置
|
||||
* 六:用户模块:登陆、注册、会员卡等
|
||||
* 七:其他等
|
||||
|
||||
|
||||
#### 已经完成功能
|
||||
- 可以具体查看演示地址查看当前版本已经完成的功能,不再絮叨啦
|
||||
|
||||
|
||||
|
||||
#### 项目结构
|
||||
项目采用分模块开发方式
|
||||
- yshop-api 公众号(H5)API模块
|
||||
- yshop-mp 微信相关模块
|
||||
- yshop-common 公共模块
|
||||
- yshop-system 商城系统模块
|
||||
- yshop-logging 日志模块
|
||||
- yshop-tools 第三方工具模块
|
||||
- yshop-generator 代码生成模块
|
||||
|
||||
#### 系统预览
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="https://images.gitee.com/uploads/images/2019/1107/194017_9207632f_477893.png"/></td>
|
||||
<td><img src="https://images.gitee.com/uploads/images/2019/1107/194030_70f5ce92_477893.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://images.gitee.com/uploads/images/2019/1107/194114_cd0b06ce_477893.png"/></td>
|
||||
<td><img src="https://images.gitee.com/uploads/images/2019/1107/194130_abb4f788_477893.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://images.gitee.com/uploads/images/2019/1107/194147_63de73f4_477893.png"/></td>
|
||||
<td><img src="https://images.gitee.com/uploads/images/2019/1107/194207_7b3b1f53_477893.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://images.gitee.com/uploads/images/2019/1107/194217_3f47214f_477893.png"/></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table>
|
||||
<tr>
|
||||
<td><img src="https://images.gitee.com/uploads/images/2019/1107/201443_df1cc3a6_477893.png"/></td>
|
||||
<td><img src="https://images.gitee.com/uploads/images/2019/1107/201540_ef6123a9_477893.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://images.gitee.com/uploads/images/2019/1107/201601_acd0ccd3_477893.png"/></td>
|
||||
<td><img src="https://images.gitee.com/uploads/images/2019/1107/201622_f913b59c_477893.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://images.gitee.com/uploads/images/2019/1107/201646_5bc6df48_477893.png"/></td>
|
||||
<td><img src="https://images.gitee.com/uploads/images/2019/1107/201706_32ee305c_477893.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
## 技术选型
|
||||
* 1 后端使用技术
|
||||
* 1.1 SpringBoot
|
||||
* 1.2 mybatis、MyBatis-Plus
|
||||
* 1.3 SpringSecurity
|
||||
* 1.4 JAP
|
||||
* 1.5 Druid1
|
||||
* 1.6 Slf4j
|
||||
* 1.7 Fastjson
|
||||
* 1.8 JWT
|
||||
* 1.9 Redis
|
||||
* 1.10 Quartz
|
||||
* 1.11 Mysql
|
||||
* 1.12 swagger
|
||||
* 1.13 WxJava
|
||||
* 1.14 Lombok
|
||||
* 1.15 Hutool
|
||||
* 1.16 Mapstruct
|
||||
|
||||
* 前端使用技术
|
||||
* 2.1 Vue 全家桶
|
||||
* 2.2 Element
|
||||
|
||||
|
||||
#### 项目发布明细
|
||||
1.0版本
|
||||
1.1版本新增积分与优惠券抵扣
|
||||
1.2版本分销功能已经发布
|
||||
1.2.1增加了未付款订单取消功能库存销量退出、优惠券、积分功能,个人中心增加了积分流水
|
||||
|
||||
#### 反馈交流
|
||||
- QQ交流群:907721261
|
||||
- 喜欢这个商城后台的小伙伴留下你的小星星啦,star,star哦!
|
||||
|
||||
#### 特别鸣谢
|
||||
- eladmin:https://github.com/elunez/eladmin
|
||||
- mybaitsplus:https://github.com/baomidou/mybatis-plus
|
||||
- hutool:https://github.com/looly/hutool
|
||||
- wxjava:https://github.com/Wechat-Group/WxJava
|
||||
- vue:https://github.com/vuejs/vue
|
||||
- element:https://github.com/ElemeFE/element
|
67
build/build.js
Normal file
@ -0,0 +1,67 @@
|
||||
'use strict'
|
||||
require('./check-versions')()
|
||||
|
||||
const ora = require('ora')
|
||||
const rm = require('rimraf')
|
||||
const path = require('path')
|
||||
const chalk = require('chalk')
|
||||
const webpack = require('webpack')
|
||||
const config = require('../config')
|
||||
const webpackConfig = require('./webpack.prod.conf')
|
||||
var connect = require('connect')
|
||||
var serveStatic = require('serve-static')
|
||||
|
||||
const spinner = ora(
|
||||
'building for ' + process.env.env_config + ' environment...'
|
||||
)
|
||||
spinner.start()
|
||||
|
||||
rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => {
|
||||
if (err) throw err
|
||||
webpack(webpackConfig, (err, stats) => {
|
||||
spinner.stop()
|
||||
if (err) throw err
|
||||
process.stdout.write(
|
||||
stats.toString({
|
||||
colors: true,
|
||||
modules: false,
|
||||
children: false,
|
||||
chunks: false,
|
||||
chunkModules: false
|
||||
}) + '\n\n'
|
||||
)
|
||||
|
||||
if (stats.hasErrors()) {
|
||||
console.log(chalk.red(' Build failed with errors.\n'))
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
console.log(chalk.cyan(' Build complete.\n'))
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
' Tip: built files are meant to be served over an HTTP server.\n' +
|
||||
" Opening index.html over file:// won't work.\n"
|
||||
)
|
||||
)
|
||||
|
||||
if (process.env.npm_config_preview) {
|
||||
const port = 9526
|
||||
const host = 'http://localhost:' + port
|
||||
const basePath = config.build.assetsPublicPath
|
||||
const app = connect()
|
||||
|
||||
app.use(
|
||||
basePath,
|
||||
serveStatic('./dist', {
|
||||
index: ['index.html', '/']
|
||||
})
|
||||
)
|
||||
|
||||
app.listen(port, function() {
|
||||
console.log(
|
||||
chalk.green(`> Listening at http://localhost:${port}${basePath}`)
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
||||
})
|
62
build/check-versions.js
Normal file
@ -0,0 +1,62 @@
|
||||
'use strict'
|
||||
const chalk = require('chalk')
|
||||
const semver = require('semver')
|
||||
const packageConfig = require('../package.json')
|
||||
const shell = require('shelljs')
|
||||
|
||||
function exec(cmd) {
|
||||
return require('child_process')
|
||||
.execSync(cmd)
|
||||
.toString()
|
||||
.trim()
|
||||
}
|
||||
|
||||
const versionRequirements = [
|
||||
{
|
||||
name: 'node',
|
||||
currentVersion: semver.clean(process.version),
|
||||
versionRequirement: packageConfig.engines.node
|
||||
}
|
||||
]
|
||||
|
||||
if (shell.which('npm')) {
|
||||
versionRequirements.push({
|
||||
name: 'npm',
|
||||
currentVersion: exec('npm --version'),
|
||||
versionRequirement: packageConfig.engines.npm
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = function() {
|
||||
const warnings = []
|
||||
|
||||
for (let i = 0; i < versionRequirements.length; i++) {
|
||||
const mod = versionRequirements[i]
|
||||
|
||||
if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) {
|
||||
warnings.push(
|
||||
mod.name +
|
||||
': ' +
|
||||
chalk.red(mod.currentVersion) +
|
||||
' should be ' +
|
||||
chalk.green(mod.versionRequirement)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (warnings.length) {
|
||||
console.log('')
|
||||
console.log(
|
||||
chalk.yellow(
|
||||
'To use this template, you must update following to modules:'
|
||||
)
|
||||
)
|
||||
|
||||
for (let i = 0; i < warnings.length; i++) {
|
||||
const warning = warnings[i]
|
||||
console.log(' ' + warning)
|
||||
}
|
||||
|
||||
process.exit(1)
|
||||
}
|
||||
}
|
108
build/utils.js
Normal file
@ -0,0 +1,108 @@
|
||||
'use strict'
|
||||
const path = require('path')
|
||||
const config = require('../config')
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
const packageConfig = require('../package.json')
|
||||
|
||||
exports.assetsPath = function(_path) {
|
||||
const assetsSubDirectory =
|
||||
process.env.NODE_ENV === 'production'
|
||||
? config.build.assetsSubDirectory
|
||||
: config.dev.assetsSubDirectory
|
||||
|
||||
return path.posix.join(assetsSubDirectory, _path)
|
||||
}
|
||||
|
||||
exports.cssLoaders = function(options) {
|
||||
options = options || {}
|
||||
|
||||
const cssLoader = {
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
sourceMap: options.sourceMap
|
||||
}
|
||||
}
|
||||
|
||||
const postcssLoader = {
|
||||
loader: 'postcss-loader',
|
||||
options: {
|
||||
sourceMap: options.sourceMap
|
||||
}
|
||||
}
|
||||
|
||||
// generate loader string to be used with extract text plugin
|
||||
function generateLoaders(loader, loaderOptions) {
|
||||
const loaders = []
|
||||
|
||||
// Extract CSS when that option is specified
|
||||
// (which is the case during production build)
|
||||
if (options.extract) {
|
||||
loaders.push(MiniCssExtractPlugin.loader)
|
||||
} else {
|
||||
loaders.push('vue-style-loader')
|
||||
}
|
||||
|
||||
loaders.push(cssLoader)
|
||||
|
||||
if (options.usePostCSS) {
|
||||
loaders.push(postcssLoader)
|
||||
}
|
||||
|
||||
if (loader) {
|
||||
loaders.push({
|
||||
loader: loader + '-loader',
|
||||
options: Object.assign({}, loaderOptions, {
|
||||
sourceMap: options.sourceMap
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
return loaders
|
||||
}
|
||||
// https://vue-loader.vuejs.org/en/configurations/extract-css.html
|
||||
return {
|
||||
css: generateLoaders(),
|
||||
postcss: generateLoaders(),
|
||||
less: generateLoaders('less'),
|
||||
sass: generateLoaders('sass', {
|
||||
indentedSyntax: true
|
||||
}),
|
||||
scss: generateLoaders('sass'),
|
||||
stylus: generateLoaders('stylus'),
|
||||
styl: generateLoaders('stylus')
|
||||
}
|
||||
}
|
||||
|
||||
// Generate loaders for standalone style files (outside of .vue)
|
||||
exports.styleLoaders = function(options) {
|
||||
const output = []
|
||||
const loaders = exports.cssLoaders(options)
|
||||
|
||||
for (const extension in loaders) {
|
||||
const loader = loaders[extension]
|
||||
output.push({
|
||||
test: new RegExp('\\.' + extension + '$'),
|
||||
use: loader
|
||||
})
|
||||
}
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
exports.createNotifierCallback = () => {
|
||||
const notifier = require('node-notifier')
|
||||
|
||||
return (severity, errors) => {
|
||||
if (severity !== 'error') return
|
||||
|
||||
const error = errors[0]
|
||||
const filename = error.file && error.file.split('!').pop()
|
||||
|
||||
notifier.notify({
|
||||
title: packageConfig.name,
|
||||
message: severity + ': ' + error.name,
|
||||
subtitle: filename || '',
|
||||
icon: path.join(__dirname, 'logo.png')
|
||||
})
|
||||
}
|
||||
}
|
5
build/vue-loader.conf.js
Normal file
@ -0,0 +1,5 @@
|
||||
'use strict'
|
||||
|
||||
module.exports = {
|
||||
//You can set the vue-loader configuration by yourself.
|
||||
}
|
122
build/webpack.base.conf.js
Normal file
@ -0,0 +1,122 @@
|
||||
'use strict'
|
||||
const path = require('path')
|
||||
const utils = require('./utils')
|
||||
const config = require('../config')
|
||||
const { VueLoaderPlugin } = require('vue-loader')
|
||||
|
||||
const os = require('os');
|
||||
const HappyPack = require('happypack');
|
||||
const happThreadPool = HappyPack.ThreadPool({size: os.cpus().length});
|
||||
|
||||
function resolve(dir) {
|
||||
return path.join(__dirname, '..', dir)
|
||||
}
|
||||
|
||||
const createLintingRule = () => ({
|
||||
// test: /\.(js|vue)$/,
|
||||
// loader: 'eslint-loader',
|
||||
// enforce: 'pre',
|
||||
// include: [resolve('src'), resolve('test')],
|
||||
// options: {
|
||||
// formatter: require('eslint-friendly-formatter'),
|
||||
// emitWarning: !config.dev.showEslintErrorsInOverlay
|
||||
// }
|
||||
})
|
||||
|
||||
module.exports = {
|
||||
cache: true,
|
||||
context: path.resolve(__dirname, '../'),
|
||||
entry:["babel-polyfill","./src/main.js"],
|
||||
output: {
|
||||
path: config.build.assetsRoot,
|
||||
filename: '[name].js',
|
||||
publicPath:
|
||||
process.env.NODE_ENV === 'production'
|
||||
? config.build.assetsPublicPath
|
||||
: config.dev.assetsPublicPath
|
||||
},
|
||||
resolve: {
|
||||
modules: [path.resolve(__dirname, '../node_modules')],
|
||||
extensions: ['.js', '.vue', '.json'],
|
||||
alias: {
|
||||
'@': resolve('src'),
|
||||
api: path.resolve(__dirname, '../src/api')
|
||||
}
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
...(config.dev.useEslint ? [createLintingRule()] : []),
|
||||
{
|
||||
test: /\.vue$/,
|
||||
loader: 'vue-loader',
|
||||
options: {
|
||||
loaders: {
|
||||
js: 'happypack/loader?id=js' // 将loader换成happypack
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
loader: ['happypack/loader?id=js'], // 将loader换成happypack
|
||||
include: [
|
||||
resolve('src')
|
||||
], // src是项目开发的目录
|
||||
exclude: [path.resolve('../node_modules')] // 不需要编译node_modules下的js
|
||||
},
|
||||
{
|
||||
test: /\.svg$/,
|
||||
loader: 'svg-sprite-loader',
|
||||
include: [resolve('src/icons')],
|
||||
options: {
|
||||
symbolId: 'icon-[name]'
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
exclude: [resolve('src/icons')],
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: utils.assetsPath('img/[name].[hash:7].[ext]')
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: utils.assetsPath('media/[name].[hash:7].[ext]')
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 10000,
|
||||
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new VueLoaderPlugin(),
|
||||
new HappyPack({
|
||||
id: 'js',
|
||||
cache: true,
|
||||
loaders: ['babel-loader?cacheDirectory=true'],
|
||||
threadPool: happThreadPool
|
||||
})
|
||||
],
|
||||
node: {
|
||||
// prevent webpack from injecting useless setImmediate polyfill because Vue
|
||||
// source contains it (although only uses it if it's native).
|
||||
setImmediate: false,
|
||||
// prevent webpack from injecting mocks to Node native modules
|
||||
// that does not make sense for the client
|
||||
dgram: 'empty',
|
||||
fs: 'empty',
|
||||
net: 'empty',
|
||||
tls: 'empty',
|
||||
child_process: 'empty'
|
||||
}
|
||||
}
|
98
build/webpack.dev.conf.js
Normal file
@ -0,0 +1,98 @@
|
||||
'use strict'
|
||||
const path = require('path')
|
||||
const utils = require('./utils')
|
||||
const webpack = require('webpack')
|
||||
const config = require('../config')
|
||||
const merge = require('webpack-merge')
|
||||
const baseWebpackConfig = require('./webpack.base.conf')
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin')
|
||||
const portfinder = require('portfinder')
|
||||
|
||||
function resolve(dir) {
|
||||
return path.join(__dirname, '..', dir)
|
||||
}
|
||||
|
||||
const HOST = process.env.HOST
|
||||
const PORT = process.env.PORT && Number(process.env.PORT)
|
||||
|
||||
const devWebpackConfig = merge(baseWebpackConfig, {
|
||||
mode: 'development',
|
||||
module: {
|
||||
rules: utils.styleLoaders({
|
||||
sourceMap: config.dev.cssSourceMap,
|
||||
usePostCSS: true
|
||||
})
|
||||
},
|
||||
// cheap-module-eval-source-map is faster for development
|
||||
devtool: config.dev.devtool,
|
||||
|
||||
// these devServer options should be customized in /config/index.js
|
||||
devServer: {
|
||||
clientLogLevel: 'warning',
|
||||
historyApiFallback: true,
|
||||
hot: true,
|
||||
compress: true,
|
||||
host: HOST || config.dev.host,
|
||||
port: PORT || config.dev.port,
|
||||
open: config.dev.autoOpenBrowser,
|
||||
overlay: config.dev.errorOverlay
|
||||
? { warnings: false, errors: true }
|
||||
: false,
|
||||
publicPath: config.dev.assetsPublicPath,
|
||||
proxy: config.dev.proxyTable,
|
||||
quiet: true, // necessary for FriendlyErrorsPlugin
|
||||
watchOptions: {
|
||||
poll: config.dev.poll
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': require('../config/dev.env')
|
||||
}),
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
// https://github.com/ampedandwired/html-webpack-plugin
|
||||
new HtmlWebpackPlugin({
|
||||
filename: 'index.html',
|
||||
template: 'index.html',
|
||||
inject: true,
|
||||
favicon: resolve('favicon.ico'),
|
||||
title: 'vue-element-admin',
|
||||
templateParameters: {
|
||||
BASE_URL: config.dev.assetsPublicPath + config.dev.assetsSubDirectory,
|
||||
},
|
||||
}),
|
||||
]
|
||||
})
|
||||
|
||||
module.exports = new Promise((resolve, reject) => {
|
||||
portfinder.basePort = process.env.PORT || config.dev.port
|
||||
portfinder.getPort((err, port) => {
|
||||
if (err) {
|
||||
reject(err)
|
||||
} else {
|
||||
// publish the new Port, necessary for e2e tests
|
||||
process.env.PORT = port
|
||||
// add port to devServer config
|
||||
devWebpackConfig.devServer.port = port
|
||||
|
||||
// Add FriendlyErrorsPlugin
|
||||
devWebpackConfig.plugins.push(
|
||||
new FriendlyErrorsPlugin({
|
||||
compilationSuccessInfo: {
|
||||
messages: [
|
||||
`Your application is running here: http://${
|
||||
devWebpackConfig.devServer.host
|
||||
}:${port}`
|
||||
]
|
||||
},
|
||||
onErrors: config.dev.notifyOnErrors
|
||||
? utils.createNotifierCallback()
|
||||
: undefined
|
||||
})
|
||||
)
|
||||
|
||||
resolve(devWebpackConfig)
|
||||
}
|
||||
})
|
||||
})
|
188
build/webpack.prod.conf.js
Normal file
@ -0,0 +1,188 @@
|
||||
'use strict'
|
||||
const path = require('path')
|
||||
const utils = require('./utils')
|
||||
const webpack = require('webpack')
|
||||
const config = require('../config')
|
||||
const merge = require('webpack-merge')
|
||||
const baseWebpackConfig = require('./webpack.base.conf')
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin')
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin')
|
||||
const ScriptExtHtmlWebpackPlugin = require('script-ext-html-webpack-plugin')
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
|
||||
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
|
||||
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')
|
||||
|
||||
function resolve(dir) {
|
||||
return path.join(__dirname, '..', dir)
|
||||
}
|
||||
|
||||
const env = require('../config/' + process.env.env_config + '.env')
|
||||
|
||||
// For NamedChunksPlugin
|
||||
const seen = new Set()
|
||||
const nameLength = 4
|
||||
|
||||
const webpackConfig = merge(baseWebpackConfig, {
|
||||
mode: 'production',
|
||||
module: {
|
||||
rules: utils.styleLoaders({
|
||||
sourceMap: config.build.productionSourceMap,
|
||||
extract: true,
|
||||
usePostCSS: true
|
||||
})
|
||||
},
|
||||
devtool: config.build.productionSourceMap ? config.build.devtool : false,
|
||||
output: {
|
||||
path: config.build.assetsRoot,
|
||||
filename: utils.assetsPath('js/[name].[chunkhash:8].js'),
|
||||
chunkFilename: utils.assetsPath('js/[name].[chunkhash:8].js')
|
||||
},
|
||||
plugins: [
|
||||
// http://vuejs.github.io/vue-loader/en/workflow/production.html
|
||||
new webpack.DefinePlugin({
|
||||
'process.env': env
|
||||
}),
|
||||
// extract css into its own file
|
||||
new MiniCssExtractPlugin({
|
||||
filename: utils.assetsPath('css/[name].[contenthash:8].css'),
|
||||
chunkFilename: utils.assetsPath('css/[name].[contenthash:8].css')
|
||||
}),
|
||||
// generate dist index.html with correct asset hash for caching.
|
||||
// you can customize output by editing /index.html
|
||||
// see https://github.com/ampedandwired/html-webpack-plugin
|
||||
new HtmlWebpackPlugin({
|
||||
filename: config.build.index,
|
||||
template: 'index.html',
|
||||
inject: true,
|
||||
favicon: resolve('favicon.ico'),
|
||||
title: 'vue-element-admin',
|
||||
templateParameters: {
|
||||
BASE_URL: config.build.assetsPublicPath + config.build.assetsSubDirectory,
|
||||
},
|
||||
minify: {
|
||||
removeComments: true,
|
||||
collapseWhitespace: true,
|
||||
removeAttributeQuotes: true
|
||||
// more options:
|
||||
// https://github.com/kangax/html-minifier#options-quick-reference
|
||||
}
|
||||
// default sort mode uses toposort which cannot handle cyclic deps
|
||||
// in certain cases, and in webpack 4, chunk order in HTML doesn't
|
||||
// matter anyway
|
||||
}),
|
||||
new ScriptExtHtmlWebpackPlugin({
|
||||
//`runtime` must same as runtimeChunk name. default is `runtime`
|
||||
inline: /runtime\..*\.js$/
|
||||
}),
|
||||
// keep chunk.id stable when chunk has no name
|
||||
new webpack.NamedChunksPlugin(chunk => {
|
||||
if (chunk.name) {
|
||||
return chunk.name
|
||||
}
|
||||
const modules = Array.from(chunk.modulesIterable)
|
||||
if (modules.length > 1) {
|
||||
const hash = require('hash-sum')
|
||||
const joinedHash = hash(modules.map(m => m.id).join('_'))
|
||||
let len = nameLength
|
||||
while (seen.has(joinedHash.substr(0, len))) len++
|
||||
seen.add(joinedHash.substr(0, len))
|
||||
return `chunk-${joinedHash.substr(0, len)}`
|
||||
} else {
|
||||
return modules[0].id
|
||||
}
|
||||
}),
|
||||
// keep module.id stable when vender modules does not change
|
||||
new webpack.HashedModuleIdsPlugin(),
|
||||
// copy custom static assets
|
||||
new CopyWebpackPlugin([
|
||||
{
|
||||
from: path.resolve(__dirname, '../static'),
|
||||
to: config.build.assetsSubDirectory,
|
||||
ignore: ['.*']
|
||||
}
|
||||
])
|
||||
],
|
||||
optimization: {
|
||||
splitChunks: {
|
||||
chunks: 'all',
|
||||
cacheGroups: {
|
||||
libs: {
|
||||
name: 'chunk-libs',
|
||||
test: /[\\/]node_modules[\\/]/,
|
||||
priority: 10,
|
||||
chunks: 'initial' // 只打包初始时依赖的第三方
|
||||
},
|
||||
elementUI: {
|
||||
name: 'chunk-elementUI', // 单独将 elementUI 拆包
|
||||
priority: 20, // 权重要大于 libs 和 app 不然会被打包进 libs 或者 app
|
||||
test: /[\\/]node_modules[\\/]element-ui[\\/]/
|
||||
},
|
||||
commons: {
|
||||
name: 'chunk-commons',
|
||||
test: resolve('src/components'), // 可自定义拓展你的规则
|
||||
minChunks: 3, // 最小公用次数
|
||||
priority: 5,
|
||||
reuseExistingChunk: true
|
||||
}
|
||||
}
|
||||
},
|
||||
runtimeChunk: 'single',
|
||||
minimizer: [
|
||||
new UglifyJsPlugin({
|
||||
uglifyOptions: {
|
||||
mangle: {
|
||||
safari10: true
|
||||
}
|
||||
},
|
||||
sourceMap: config.build.productionSourceMap,
|
||||
cache: true,
|
||||
parallel: true
|
||||
}),
|
||||
// Compress extracted CSS. We are using this plugin so that possible
|
||||
// duplicated CSS from different components can be deduped.
|
||||
new OptimizeCSSAssetsPlugin()
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
if (config.build.productionGzip) {
|
||||
const CompressionWebpackPlugin = require('compression-webpack-plugin')
|
||||
|
||||
webpackConfig.plugins.push(
|
||||
new CompressionWebpackPlugin({
|
||||
asset: '[path].gz[query]',
|
||||
algorithm: 'gzip',
|
||||
test: new RegExp(
|
||||
'\\.(' + config.build.productionGzipExtensions.join('|') + ')$'
|
||||
),
|
||||
threshold: 10240,
|
||||
minRatio: 0.8
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
if (config.build.generateAnalyzerReport || config.build.bundleAnalyzerReport) {
|
||||
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer')
|
||||
.BundleAnalyzerPlugin
|
||||
|
||||
if (config.build.bundleAnalyzerReport) {
|
||||
webpackConfig.plugins.push(
|
||||
new BundleAnalyzerPlugin({
|
||||
analyzerPort: 8080,
|
||||
generateStatsFile: false
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
if (config.build.generateAnalyzerReport) {
|
||||
webpackConfig.plugins.push(
|
||||
new BundleAnalyzerPlugin({
|
||||
analyzerMode: 'static',
|
||||
reportFilename: 'bundle-report.html',
|
||||
openAnalyzer: false
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = webpackConfig
|
9
config/dev.env.js
Normal file
@ -0,0 +1,9 @@
|
||||
'use strict'
|
||||
const merge = require('webpack-merge')
|
||||
const prodEnv = require('./prod.env')
|
||||
|
||||
module.exports = merge(prodEnv, {
|
||||
NODE_ENV: '"development"',
|
||||
BASE_API: '"http://localhost:8000"'
|
||||
// BASE_API: '"https://api.auauz.net"'
|
||||
})
|
106
config/index.js
Normal file
@ -0,0 +1,106 @@
|
||||
'use strict'
|
||||
// Template version: 1.2.6
|
||||
const devEnv = require('./dev.env')
|
||||
// 获取接口地址
|
||||
const base_url = devEnv.BASE_API.replace(/"/g,'')
|
||||
const path = require('path')
|
||||
module.exports = {
|
||||
dev: {
|
||||
// Paths
|
||||
assetsSubDirectory: 'static',
|
||||
assetsPublicPath: '/',
|
||||
// 配置代理
|
||||
proxyTable: {
|
||||
'/auth': {
|
||||
// 测试环境
|
||||
target: base_url,
|
||||
secure: true,
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
'^/auth': 'auth'
|
||||
}
|
||||
},
|
||||
'/api': {
|
||||
// 测试环境
|
||||
target: base_url,
|
||||
secure: true,
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
'^/api': 'api'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Various Dev Server settings
|
||||
host: 'localhost', // can be overwritten by process.env.HOST
|
||||
port: 8013, // can be overwritten by process.env.PORT, if port is in use, a free one will be determined
|
||||
autoOpenBrowser: true,
|
||||
errorOverlay: true,
|
||||
notifyOnErrors: false,
|
||||
poll: false, // https://webpack.js.org/configuration/dev-server/#devserver-watchoptions-
|
||||
|
||||
// Use Eslint Loader?
|
||||
// If true, your code will be linted during bundling and
|
||||
// linting errors and warnings will be shown in the console.
|
||||
useEslint: true,
|
||||
// If true, eslint errors and warnings will also be shown in the error overlay
|
||||
// in the browser.
|
||||
showEslintErrorsInOverlay: false,
|
||||
|
||||
/**
|
||||
* Source Maps
|
||||
*/
|
||||
|
||||
// https://webpack.js.org/configuration/devtool/#development
|
||||
devtool: 'cheap-source-map',
|
||||
|
||||
// CSS Sourcemaps off by default because relative paths are "buggy"
|
||||
// with this option, according to the CSS-Loader README
|
||||
// (https://github.com/webpack/css-loader#sourcemaps)
|
||||
// In our experience, they generally work as expected,
|
||||
// just be aware of this issue when enabling this option.
|
||||
cssSourceMap: false
|
||||
},
|
||||
|
||||
build: {
|
||||
// Template for index.html
|
||||
index: path.resolve(__dirname, '../dist/index.html'),
|
||||
|
||||
// Paths
|
||||
assetsRoot: path.resolve(__dirname, '../dist'),
|
||||
assetsSubDirectory: 'static',
|
||||
|
||||
/**
|
||||
* You can set by youself according to actual condition
|
||||
* You will need to set this if you plan to deploy your site under a sub path,
|
||||
* for example GitHub pages. If you plan to deploy your site to https://foo.github.io/bar/,
|
||||
* then assetsPublicPath should be set to "/bar/".
|
||||
* In most cases please use '/' !!!
|
||||
*/
|
||||
assetsPublicPath: '/',
|
||||
|
||||
/**
|
||||
* Source Maps
|
||||
*/
|
||||
|
||||
productionSourceMap: false,
|
||||
// https://webpack.js.org/configuration/devtool/#production
|
||||
devtool: 'source-map',
|
||||
|
||||
// Gzip off by default as many popular static hosts such as
|
||||
// Surge or Netlify already gzip all static assets for you.
|
||||
// Before setting to `true`, make sure to:
|
||||
// npm install --save-dev compression-webpack-plugin
|
||||
productionGzip: false,
|
||||
productionGzipExtensions: ['js', 'css'],
|
||||
|
||||
// Run the build command with an extra argument to
|
||||
// View the bundle analyzer report after build finishes:
|
||||
// `npm run build --report`
|
||||
// Set to `true` or `false` to always turn it on or off
|
||||
bundleAnalyzerReport: process.env.npm_config_report || false,
|
||||
|
||||
// `npm run build:prod --generate_report`
|
||||
generateAnalyzerReport: process.env.npm_config_generate_report || false
|
||||
}
|
||||
}
|
5
config/prod.env.js
Normal file
@ -0,0 +1,5 @@
|
||||
'use strict'
|
||||
module.exports = {
|
||||
NODE_ENV: '"production"',
|
||||
BASE_API: '"https://yshopapi.dayouqiantu.cn"'
|
||||
}
|
1
debug.log
Normal file
@ -0,0 +1 @@
|
||||
[1110/193651.524:ERROR:crashpad_client_win.cc(491)] CreateProcess: ҳ<><D2B3><EFBFBD>ļ<EFBFBD>̫С<CCAB><D0A1><EFBFBD><EFBFBD><DEB7><EFBFBD><EFBFBD>ɲ<EFBFBD><C9B2><EFBFBD><EFBFBD><EFBFBD> (0x5AF)
|
BIN
favicon.ico
Normal file
After Width: | Height: | Size: 1.2 KiB |
22
index.html
Normal file
@ -0,0 +1,22 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<style>
|
||||
.sampleContainer{position:fixed;top:50%;left:50%;-webkit-transform:translateX(-50%) translateY(-50%);width:75px;height:100px}.loader{position:relative;width:44px;height:8px;margin:12px auto}.dot{display:inline-block;width:8px;height:8px;border-radius:4px;background:#ccc;position:absolute}.dot_1{animation:animateDot1 1.5s linear infinite;left:12px;background:#e579b8}.dot_2{animation:animateDot2 1.5s linear infinite;animation-delay:.5s;left:24px}.dot_3{animation:animateDot3 1.5s linear infinite;left:12px}.dot_4{animation:animateDot4 1.5s linear infinite;animation-delay:.5s;left:24px}@keyframes animateDot1{0%{transform:rotate(0) translateX(-12px)}25%{transform:rotate(180deg) translateX(-12px)}75%{transform:rotate(180deg) translateX(-12px)}100%{transform:rotate(360deg) translateX(-12px)}}@keyframes animateDot2{0%{transform:rotate(0) translateX(-12px)}25%{transform:rotate(-180deg) translateX(-12px)}75%{transform:rotate(-180deg) translateX(-12px)}100%{transform:rotate(-360deg) translateX(-12px)}}@keyframes animateDot3{0%{transform:rotate(0) translateX(12px)}25%{transform:rotate(180deg) translateX(12px)}75%{transform:rotate(180deg) translateX(12px)}100%{transform:rotate(360deg) translateX(12px)}}@keyframes animateDot4{0%{transform:rotate(0) translateX(12px)}25%{transform:rotate(-180deg) translateX(12px)}75%{transform:rotate(-180deg) translateX(12px)}100%{transform:rotate(-360deg) translateX(12px)}}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app">
|
||||
<div class="sampleContainer">
|
||||
<div class="loader">
|
||||
<span class="dot dot_1"></span>
|
||||
<span class="dot dot_2"></span>
|
||||
<span class="dot dot_3"></span>
|
||||
<span class="dot dot_4"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
106
package.json
Normal file
@ -0,0 +1,106 @@
|
||||
{
|
||||
"name": "YSHOP",
|
||||
"version": "2.2.0",
|
||||
"license": "Apache-2.0",
|
||||
"description": "YSHOP 前端代码",
|
||||
"author": "hupeng <610796224@qq.com>",
|
||||
"scripts": {
|
||||
"dev": "cross-env BABEL_ENV=development webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
|
||||
"build": "cross-env NODE_ENV=production env_config=prod node build/build.js",
|
||||
"lint": "eslint --ext .js,.vue src",
|
||||
"test": "npm run lint",
|
||||
"precommit": "lint-staged",
|
||||
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/elunez/eladmin-qd"
|
||||
},
|
||||
"dependencies": {
|
||||
"@riophae/vue-treeselect": "0.0.38",
|
||||
"axios": "^0.19.0",
|
||||
"clipboard": "1.7.1",
|
||||
"codemirror": "^5.38.0",
|
||||
"connect": "3.6.6",
|
||||
"echarts": "4.1.0",
|
||||
"element-ui": "^2.12.0",
|
||||
"file-saver": "1.3.8",
|
||||
"js-cookie": "2.2.0",
|
||||
"jsencrypt": "^3.0.0-rc.1",
|
||||
"jszip": "3.1.5",
|
||||
"mavon-editor": "^2.7.0",
|
||||
"normalize.css": "7.0.0",
|
||||
"nprogress": "0.2.0",
|
||||
"path-to-regexp": "2.4.0",
|
||||
"screenfull": "3.3.3",
|
||||
"vue": "2.5.17",
|
||||
"vue-count-to": "1.0.13",
|
||||
"vue-router": "3.1.3",
|
||||
"vuex": "3.0.1",
|
||||
"wangeditor": ">=3.0.0",
|
||||
"xlsx": "^0.11.16"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "8.5.0",
|
||||
"babel-core": "6.26.3",
|
||||
"babel-eslint": "8.2.6",
|
||||
"babel-helper-vue-jsx-merge-props": "2.0.3",
|
||||
"babel-loader": "7.1.5",
|
||||
"babel-plugin-dynamic-import-node": "2.0.0",
|
||||
"babel-plugin-syntax-jsx": "6.18.0",
|
||||
"babel-plugin-transform-runtime": "6.23.0",
|
||||
"babel-plugin-transform-vue-jsx": "3.7.0",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"babel-preset-env": "1.7.0",
|
||||
"babel-preset-stage-2": "6.24.1",
|
||||
"chalk": "2.4.1",
|
||||
"copy-webpack-plugin": "4.5.2",
|
||||
"cross-env": "5.2.0",
|
||||
"css-loader": "1.0.0",
|
||||
"eslint": "4.19.1",
|
||||
"eslint-friendly-formatter": "4.0.1",
|
||||
"eslint-loader": "2.0.0",
|
||||
"eslint-plugin-vue": "4.7.1",
|
||||
"eventsource-polyfill": "0.9.6",
|
||||
"file-loader": "1.1.11",
|
||||
"friendly-errors-webpack-plugin": "1.7.0",
|
||||
"happypack": "^5.0.1",
|
||||
"html-webpack-plugin": "4.0.0-alpha",
|
||||
"mini-css-extract-plugin": "0.4.1",
|
||||
"node-notifier": "5.2.1",
|
||||
"node-sass": "^4.7.2",
|
||||
"optimize-css-assets-webpack-plugin": "5.0.0",
|
||||
"ora": "3.0.0",
|
||||
"portfinder": "1.0.16",
|
||||
"postcss-import": "12.0.0",
|
||||
"postcss-loader": "2.1.6",
|
||||
"postcss-url": "7.3.2",
|
||||
"rimraf": "2.6.2",
|
||||
"sass-loader": "7.0.3",
|
||||
"script-ext-html-webpack-plugin": "2.0.1",
|
||||
"script-loader": "0.7.2",
|
||||
"semver": "5.5.0",
|
||||
"shelljs": "^0.8.3",
|
||||
"svg-sprite-loader": "3.8.0",
|
||||
"svgo": "1.2.2",
|
||||
"uglifyjs-webpack-plugin": "1.2.7",
|
||||
"url-loader": "1.0.1",
|
||||
"vue-loader": "15.3.0",
|
||||
"vue-style-loader": "4.1.2",
|
||||
"vue-template-compiler": "2.5.17",
|
||||
"webpack": "4.16.5",
|
||||
"webpack-bundle-analyzer": "3.3.2",
|
||||
"webpack-cli": "3.1.0",
|
||||
"webpack-dev-server": "3.3.1",
|
||||
"webpack-merge": "4.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6.0.0",
|
||||
"npm": ">= 3.0.0"
|
||||
},
|
||||
"browserslist": [
|
||||
"> 1%",
|
||||
"last 2 versions",
|
||||
"not ie <= 8"
|
||||
]
|
||||
}
|
11
src/App.vue
Normal file
@ -0,0 +1,11 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<router-view/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'App'
|
||||
}
|
||||
</script>
|
25
src/api/alipay.js
Normal file
@ -0,0 +1,25 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function get() {
|
||||
return request({
|
||||
url: 'api/aliPay',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function update(data) {
|
||||
return request({
|
||||
url: 'api/aliPay',
|
||||
data,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
// 支付
|
||||
export function toAliPay(url, data) {
|
||||
return request({
|
||||
url: 'api/' + url,
|
||||
data,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
16
src/api/code.js
Normal file
@ -0,0 +1,16 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function resetEmail(data) {
|
||||
return request({
|
||||
url: 'api/code/resetEmail',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updatePass(pass) {
|
||||
return request({
|
||||
url: 'api/users/updatePass/' + pass,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
9
src/api/data.js
Normal file
@ -0,0 +1,9 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function initData(url, params) {
|
||||
return request({
|
||||
url: url,
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
32
src/api/dept.js
Normal file
@ -0,0 +1,32 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getDepts(params) {
|
||||
return request({
|
||||
url: 'api/dept',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/dept',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/dept/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/dept',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
24
src/api/dict.js
Normal file
@ -0,0 +1,24 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/dict',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/dict/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/dict',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
50
src/api/dictDetail.js
Normal file
@ -0,0 +1,50 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function get(dictName) {
|
||||
const params = {
|
||||
dictName,
|
||||
page: 0,
|
||||
size: 9999
|
||||
}
|
||||
return request({
|
||||
url: 'api/dictDetail',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function getDictMap(dictName) {
|
||||
const params = {
|
||||
dictName,
|
||||
page: 0,
|
||||
size: 9999
|
||||
}
|
||||
return request({
|
||||
url: 'api/dictDetail/map',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/dictDetail',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/dictDetail/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/dictDetail',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
24
src/api/email.js
Normal file
@ -0,0 +1,24 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function get() {
|
||||
return request({
|
||||
url: 'api/email',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function update(data) {
|
||||
return request({
|
||||
url: 'api/email',
|
||||
data,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
export function send(data) {
|
||||
return request({
|
||||
url: 'api/email',
|
||||
data,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
16
src/api/genConfig.js
Normal file
@ -0,0 +1,16 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function get() {
|
||||
return request({
|
||||
url: 'api/genConfig',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function update(data) {
|
||||
return request({
|
||||
url: 'api/genConfig',
|
||||
data,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
9
src/api/generator.js
Normal file
@ -0,0 +1,9 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function generator(data, tableName) {
|
||||
return request({
|
||||
url: 'api/generator?tableName=' + tableName,
|
||||
data,
|
||||
method: 'post'
|
||||
})
|
||||
}
|
37
src/api/job.js
Normal file
@ -0,0 +1,37 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getAllJob(deptId) {
|
||||
const params = {
|
||||
deptId,
|
||||
page: 0,
|
||||
size: 9999
|
||||
}
|
||||
return request({
|
||||
url: 'api/job',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/job',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/job/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/job',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
32
src/api/localStorage.js
Normal file
@ -0,0 +1,32 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/localStorage',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/localStorage/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function delAll(ids) {
|
||||
return request({
|
||||
url: 'api/localStorage/',
|
||||
method: 'delete',
|
||||
data: ids
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/localStorage',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
8
src/api/log.js
Normal file
@ -0,0 +1,8 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getErrDetail(id) {
|
||||
return request({
|
||||
url: 'api/logs/error/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
28
src/api/login.js
Normal file
@ -0,0 +1,28 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function login(username, password, code, uuid) {
|
||||
return request({
|
||||
url: 'auth/login',
|
||||
method: 'post',
|
||||
data: {
|
||||
username,
|
||||
password,
|
||||
code,
|
||||
uuid
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getInfo() {
|
||||
return request({
|
||||
url: 'auth/info',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function getCodeImg() {
|
||||
return request({
|
||||
url: 'auth/vCode',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
39
src/api/menu.js
Normal file
@ -0,0 +1,39 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获取所有的菜单树
|
||||
export function getMenusTree() {
|
||||
return request({
|
||||
url: 'api/menus/tree',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function buildMenus() {
|
||||
return request({
|
||||
url: 'api/menus/build',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/menus',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/menus/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/menus',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
32
src/api/permission.js
Normal file
@ -0,0 +1,32 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获取所有的权限树
|
||||
export function getPermissionTree() {
|
||||
return request({
|
||||
url: 'api/permissions/tree',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/permissions',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/permissions/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/permissions',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
16
src/api/picture.js
Normal file
@ -0,0 +1,16 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/pictures/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function delAll(ids) {
|
||||
return request({
|
||||
url: 'api/pictures/',
|
||||
method: 'delete',
|
||||
data: ids
|
||||
})
|
||||
}
|
45
src/api/qiniu.js
Normal file
@ -0,0 +1,45 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function get() {
|
||||
return request({
|
||||
url: 'api/qiNiuConfig',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function update(data) {
|
||||
return request({
|
||||
url: 'api/qiNiuConfig',
|
||||
data,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/qiNiuContent/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function download(id) {
|
||||
return request({
|
||||
url: 'api/qiNiuContent/download/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function sync() {
|
||||
return request({
|
||||
url: 'api/qiNiuContent/synchronize',
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
export function delAll(ids) {
|
||||
return request({
|
||||
url: 'api/qiNiuContent/',
|
||||
method: 'delete',
|
||||
data: ids
|
||||
})
|
||||
}
|
35
src/api/redis.js
Normal file
@ -0,0 +1,35 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/redis',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(key) {
|
||||
const data = {
|
||||
key
|
||||
}
|
||||
return request({
|
||||
url: 'api/redis/',
|
||||
method: 'delete',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function delAll() {
|
||||
return request({
|
||||
url: 'api/redis/all',
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/redis',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
62
src/api/role.js
Normal file
@ -0,0 +1,62 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
// 获取所有的Role
|
||||
export function getAll() {
|
||||
return request({
|
||||
url: 'api/roles/all',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/roles',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function get(id) {
|
||||
return request({
|
||||
url: 'api/roles/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function getLevel() {
|
||||
return request({
|
||||
url: 'api/roles/level',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/roles/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/roles',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function editPermission(data) {
|
||||
return request({
|
||||
url: 'api/roles/permission',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function editMenu(data) {
|
||||
return request({
|
||||
url: 'api/roles/menu',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
38
src/api/timing.js
Normal file
@ -0,0 +1,38 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/jobs',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/jobs/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/jobs',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateIsPause(id) {
|
||||
return request({
|
||||
url: 'api/jobs/' + id,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
||||
|
||||
export function execution(id) {
|
||||
return request({
|
||||
url: 'api/jobs/exec/' + id,
|
||||
method: 'put'
|
||||
})
|
||||
}
|
52
src/api/user.js
Normal file
@ -0,0 +1,52 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/users',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
export function downloadUser() {
|
||||
return request({
|
||||
url: 'api/users/download',
|
||||
method: 'get',
|
||||
responseType: 'blob'
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/users/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/users',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updatePass(user) {
|
||||
const data = {
|
||||
oldPass: user.oldPass,
|
||||
newPass: user.newPass
|
||||
}
|
||||
return request({
|
||||
url: 'api/users/updatePass/',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function updateEmail(code, data) {
|
||||
return request({
|
||||
url: 'api/users/updateEmail/' + code,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
22
src/api/visits.js
Normal file
@ -0,0 +1,22 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function count() {
|
||||
return request({
|
||||
url: 'api/visits',
|
||||
method: 'post'
|
||||
})
|
||||
}
|
||||
|
||||
export function get() {
|
||||
return request({
|
||||
url: 'api/visits',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
||||
|
||||
export function getChartData() {
|
||||
return request({
|
||||
url: 'api/visits/chartData',
|
||||
method: 'get'
|
||||
})
|
||||
}
|
31
src/api/yxArticle.js
Normal file
@ -0,0 +1,31 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/yxArticle',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/yxArticle/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/yxArticle',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function publish(id) {
|
||||
return request({
|
||||
url: 'api/yxArticle/publish/' + id,
|
||||
method: 'get'
|
||||
})
|
||||
}
|
31
src/api/yxCache.js
Normal file
@ -0,0 +1,31 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/yxCache',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(key) {
|
||||
return request({
|
||||
url: 'api/yxCache/' + key,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/yxCache',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function get() {
|
||||
return request({
|
||||
url: 'api/yxCache',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
32
src/api/yxStoreCategory.js
Normal file
@ -0,0 +1,32 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function getCates(params) {
|
||||
return request({
|
||||
url: 'api/yxStoreCategory',
|
||||
method: 'get',
|
||||
params
|
||||
})
|
||||
}
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreCategory',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/yxStoreCategory/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreCategory',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
32
src/api/yxStoreCombination.js
Normal file
@ -0,0 +1,32 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreCombination',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/yxStoreCombination/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreCombination',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function onsale(id, data) {
|
||||
return request({
|
||||
url: 'api/yxStoreCombination/onsale/' + id,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
24
src/api/yxStoreCoupon.js
Normal file
@ -0,0 +1,24 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreCoupon',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/yxStoreCoupon/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreCoupon',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
24
src/api/yxStoreCouponIssue.js
Normal file
@ -0,0 +1,24 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreCouponIssue',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/yxStoreCouponIssue/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreCouponIssue',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
24
src/api/yxStoreCouponIssueUser.js
Normal file
@ -0,0 +1,24 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreCouponIssueUser',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/yxStoreCouponIssueUser/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreCouponIssueUser',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
24
src/api/yxStoreCouponUser.js
Normal file
@ -0,0 +1,24 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreCouponUser',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/yxStoreCouponUser/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreCouponUser',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
32
src/api/yxStoreOrder.js
Normal file
@ -0,0 +1,32 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreOrder',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/yxStoreOrder/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreOrder',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function refund(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreOrder/refund',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
24
src/api/yxStoreOrderStatus.js
Normal file
@ -0,0 +1,24 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreOrderStatus',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/yxStoreOrderStatus/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreOrderStatus',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
24
src/api/yxStorePink.js
Normal file
@ -0,0 +1,24 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/yxStorePink',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/yxStorePink/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/yxStorePink',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
72
src/api/yxStoreProduct.js
Normal file
@ -0,0 +1,72 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreProduct',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/yxStoreProduct/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreProduct',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function onsale(id, data) {
|
||||
return request({
|
||||
url: 'api/yxStoreProduct/onsale/' + id,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function recovery(id) {
|
||||
return request({
|
||||
url: 'api/yxStoreProduct/recovery/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function isFormatAttr(id,data) {
|
||||
return request({
|
||||
url: 'api/yxStoreProduct/isFormatAttr/' + id,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function setAttr(id,data) {
|
||||
return request({
|
||||
url: 'api/yxStoreProduct/setAttr/' + id,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
export function clearAttr(id) {
|
||||
return request({
|
||||
url: 'api/yxStoreProduct/clearAttr/' + id,
|
||||
method: 'post',
|
||||
})
|
||||
}
|
||||
|
||||
export function getAttr(id) {
|
||||
return request({
|
||||
url: 'api/yxStoreProduct/attr/' + id,
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
||||
|
24
src/api/yxStoreProductReply.js
Normal file
@ -0,0 +1,24 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreProductReply',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/yxStoreProductReply/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreProductReply',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
24
src/api/yxStoreVisit.js
Normal file
@ -0,0 +1,24 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreVisit',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/yxStoreVisit/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/yxStoreVisit',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
32
src/api/yxSystemConfig.js
Normal file
@ -0,0 +1,32 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/yxSystemConfig',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/yxSystemConfig/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/yxSystemConfig',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function get() {
|
||||
return request({
|
||||
url: 'api/yxSystemConfig',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
24
src/api/yxSystemGroupData.js
Normal file
@ -0,0 +1,24 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/yxSystemGroupData',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/yxSystemGroupData/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/yxSystemGroupData',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
32
src/api/yxUser.js
Normal file
@ -0,0 +1,32 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/yxUser',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(uid) {
|
||||
return request({
|
||||
url: 'api/yxUser/' + uid,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/yxUser',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function onStatus(id, data) {
|
||||
return request({
|
||||
url: 'api/yxUser/onStatus/' + id,
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
24
src/api/yxUserBill.js
Normal file
@ -0,0 +1,24 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/yxUserBill',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/yxUserBill/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/yxUserBill',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
24
src/api/yxUserExtract.js
Normal file
@ -0,0 +1,24 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/yxUserExtract',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/yxUserExtract/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/yxUserExtract',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
32
src/api/yxWechatReply.js
Normal file
@ -0,0 +1,32 @@
|
||||
import request from '@/utils/request'
|
||||
|
||||
export function add(data) {
|
||||
return request({
|
||||
url: 'api/yxWechatReply',
|
||||
method: 'post',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function del(id) {
|
||||
return request({
|
||||
url: 'api/yxWechatReply/' + id,
|
||||
method: 'delete'
|
||||
})
|
||||
}
|
||||
|
||||
export function edit(data) {
|
||||
return request({
|
||||
url: 'api/yxWechatReply',
|
||||
method: 'put',
|
||||
data
|
||||
})
|
||||
}
|
||||
|
||||
export function get() {
|
||||
return request({
|
||||
url: 'api/yxWechatReply',
|
||||
method: 'get',
|
||||
})
|
||||
}
|
||||
|
BIN
src/assets/401_images/401.gif
Normal file
After Width: | Height: | Size: 160 KiB |
BIN
src/assets/404_images/404.png
Normal file
After Width: | Height: | Size: 96 KiB |
BIN
src/assets/404_images/404_cloud.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
BIN
src/assets/avatar/avatar.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
src/assets/logo/logo.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
src/assets/wechat/head.gif
Normal file
After Width: | Height: | Size: 126 KiB |
BIN
src/assets/wechat/index.png
Normal file
After Width: | Height: | Size: 231 B |
BIN
src/assets/wechat/mobile_foot.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
src/assets/wechat/mobile_head.png
Normal file
After Width: | Height: | Size: 12 KiB |
74
src/components/Breadcrumb/index.vue
Normal file
@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<el-breadcrumb class="app-breadcrumb" separator="/">
|
||||
<transition-group name="breadcrumb">
|
||||
<el-breadcrumb-item v-for="(item,index) in levelList" v-if="item.meta.title" :key="item.path">
|
||||
<span v-if="item.redirect==='noredirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
|
||||
<a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
|
||||
</el-breadcrumb-item>
|
||||
</transition-group>
|
||||
</el-breadcrumb>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import pathToRegexp from 'path-to-regexp'
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
levelList: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
$route() {
|
||||
this.getBreadcrumb()
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.getBreadcrumb()
|
||||
},
|
||||
methods: {
|
||||
getBreadcrumb() {
|
||||
let matched = this.$route.matched.filter(item => {
|
||||
if (item.name) {
|
||||
return true
|
||||
}
|
||||
})
|
||||
const first = matched[0]
|
||||
if (first && first.name !== '首页') {
|
||||
matched = [{ path: '/dashboard', meta: { title: '首页' }}].concat(matched)
|
||||
}
|
||||
if (matched.length >= 4) {
|
||||
matched.splice(1, 1)
|
||||
}
|
||||
this.levelList = matched
|
||||
},
|
||||
pathCompile(path) {
|
||||
// To solve this problem https://github.com/PanJiaChen/vue-element-admin/issues/561
|
||||
const { params } = this.$route
|
||||
var toPath = pathToRegexp.compile(path)
|
||||
return toPath(params)
|
||||
},
|
||||
handleLink(item) {
|
||||
const { redirect, path } = item
|
||||
if (redirect) {
|
||||
this.$router.push(redirect)
|
||||
return
|
||||
}
|
||||
this.$router.push(this.pathCompile(path))
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.app-breadcrumb.el-breadcrumb {
|
||||
display: inline-block;
|
||||
font-size: 14px;
|
||||
line-height: 50px;
|
||||
margin-left: 10px;
|
||||
.no-redirect {
|
||||
color: #97a8be;
|
||||
cursor: text;
|
||||
}
|
||||
}
|
||||
</style>
|
47
src/components/Hamburger/index.vue
Normal file
@ -0,0 +1,47 @@
|
||||
<template>
|
||||
<div>
|
||||
<svg
|
||||
:class="{'is-active':isActive}"
|
||||
t="1492500959545"
|
||||
class="hamburger"
|
||||
viewBox="0 0 1024 1024"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
version="1.1"
|
||||
p-id="1691"
|
||||
width="64"
|
||||
height="64"
|
||||
@click="toggleClick">
|
||||
<path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'Hamburger',
|
||||
props: {
|
||||
isActive: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
toggleClick: {
|
||||
type: Function,
|
||||
default: null
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.hamburger {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
transition: .38s;
|
||||
transform-origin: 50% 50%;
|
||||
}
|
||||
.hamburger.is-active {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
</style>
|
69
src/components/IconSelect/index.vue
Normal file
@ -0,0 +1,69 @@
|
||||
<!-- @author zhengjie -->
|
||||
<template>
|
||||
<div class="icon-body">
|
||||
<el-input v-model="name" style="position: relative;" clearable placeholder="请输入图标名称" @clear="filterIcons" @input.native="filterIcons">
|
||||
<i slot="suffix" class="el-icon-search el-input__icon"/>
|
||||
</el-input>
|
||||
<div class="icon-list">
|
||||
<div v-for="(item, index) in iconList" :key="index" @click="selectedIcon(item)">
|
||||
<svg-icon :icon-class="item" style="height: 30px;width: 16px;" />
|
||||
<span>{{ item }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import icons from './requireIcons'
|
||||
export default {
|
||||
name: 'IconSelect',
|
||||
data() {
|
||||
return {
|
||||
name: '',
|
||||
iconList: icons
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
filterIcons() {
|
||||
if (this.name) {
|
||||
this.iconList = this.iconList.filter(item => item.includes(this.name))
|
||||
} else {
|
||||
this.iconList = icons
|
||||
}
|
||||
},
|
||||
selectedIcon(name) {
|
||||
this.$emit('selected', name)
|
||||
document.body.click()
|
||||
},
|
||||
reset() {
|
||||
this.name = ''
|
||||
this.iconList = icons
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.icon-body {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
.icon-list {
|
||||
height: 200px;
|
||||
overflow-y: scroll;
|
||||
div {
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
margin-bottom: -5px;
|
||||
cursor: pointer;
|
||||
width: 33%;
|
||||
float: left;
|
||||
}
|
||||
span {
|
||||
display: inline-block;
|
||||
vertical-align: -0.15em;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
11
src/components/IconSelect/requireIcons.js
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
const req = require.context('../../icons/svg', false, /\.svg$/)
|
||||
const requireAll = requireContext => requireContext.keys()
|
||||
|
||||
const re = /\.\/(.*)\.svg/
|
||||
|
||||
const icons = requireAll(req).map(i => {
|
||||
return i.match(re)[1]
|
||||
})
|
||||
|
||||
export default icons
|
140
src/components/PanThumb/index.vue
Normal file
@ -0,0 +1,140 @@
|
||||
<template>
|
||||
<div :style="{zIndex:zIndex,height:height,width:width}" class="pan-item">
|
||||
<div class="pan-info">
|
||||
<div class="pan-info-roles-container">
|
||||
<slot/>
|
||||
</div>
|
||||
</div>
|
||||
<img :src="image" class="pan-thumb">
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'PanThumb',
|
||||
props: {
|
||||
image: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
zIndex: {
|
||||
type: Number,
|
||||
default: 1
|
||||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: '150px'
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
default: '150px'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.pan-item {
|
||||
width: 200px;
|
||||
height: 200px;
|
||||
border-radius: 50%;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
cursor: default;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.pan-info-roles-container {
|
||||
padding: 20px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.pan-thumb {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-size: 100%;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
transform-origin: 95% 40%;
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
.pan-thumb:after {
|
||||
content: '';
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
position: absolute;
|
||||
border-radius: 50%;
|
||||
top: 40%;
|
||||
left: 95%;
|
||||
margin: -4px 0 0 -4px;
|
||||
background: radial-gradient(ellipse at center, rgba(14, 14, 14, 1) 0%, rgba(125, 126, 125, 1) 100%);
|
||||
box-shadow: 0 0 1px rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
|
||||
.pan-info {
|
||||
position: absolute;
|
||||
width: inherit;
|
||||
height: inherit;
|
||||
border-radius: 50%;
|
||||
overflow: hidden;
|
||||
box-shadow: inset 0 0 0 5px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.pan-info h3 {
|
||||
color: #fff;
|
||||
text-transform: uppercase;
|
||||
position: relative;
|
||||
letter-spacing: 2px;
|
||||
font-size: 18px;
|
||||
margin: 0 60px;
|
||||
padding: 22px 0 0 0;
|
||||
height: 85px;
|
||||
font-family: 'Open Sans', Arial, sans-serif;
|
||||
text-shadow: 0 0 1px #fff, 0 1px 2px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.pan-info p {
|
||||
color: #fff;
|
||||
padding: 10px 5px;
|
||||
font-style: italic;
|
||||
margin: 0 30px;
|
||||
font-size: 12px;
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.pan-info p a {
|
||||
display: block;
|
||||
color: #333;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
background: rgba(255, 255, 255, 0.3);
|
||||
border-radius: 50%;
|
||||
color: #fff;
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
font-size: 9px;
|
||||
letter-spacing: 1px;
|
||||
padding-top: 24px;
|
||||
margin: 7px auto 0;
|
||||
font-family: 'Open Sans', Arial, sans-serif;
|
||||
opacity: 0;
|
||||
transition: transform 0.3s ease-in-out 0.2s, opacity 0.3s ease-in-out 0.2s, background 0.2s linear 0s;
|
||||
transform: translateX(60px) rotate(90deg);
|
||||
}
|
||||
|
||||
.pan-info p a:hover {
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.pan-item:hover .pan-thumb {
|
||||
transform: rotate(-110deg);
|
||||
}
|
||||
|
||||
.pan-item:hover .pan-info p a {
|
||||
opacity: 1;
|
||||
transform: translateX(0px) rotate(0deg);
|
||||
}
|
||||
</style>
|
165
src/components/RightPanel/index.vue
Normal file
@ -0,0 +1,165 @@
|
||||
<template>
|
||||
<div ref="rightPanel" :class="{show:show}" class="rightPanel-container">
|
||||
<div class="rightPanel-background" />
|
||||
<div class="rightPanel">
|
||||
<div v-if="settingBtn" :style="{'top':buttonTop+'px','background-color':theme}" class="handle-button" @click="show=!show">
|
||||
<i :class="show?'el-icon-close':'el-icon-setting'" />
|
||||
</div>
|
||||
<div v-else :style="{'top':buttonTop+'px'}" @click="show=!show"/>
|
||||
<div class="rightPanel-items">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { addClass, removeClass } from '@/utils'
|
||||
|
||||
export default {
|
||||
name: 'RightPanel',
|
||||
props: {
|
||||
clickNotClose: {
|
||||
default: false,
|
||||
type: Boolean
|
||||
},
|
||||
buttonTop: {
|
||||
default: 250,
|
||||
type: Number
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
show: {
|
||||
get() {
|
||||
return this.$store.state.settings.showRightPanel
|
||||
},
|
||||
set(val) {
|
||||
this.$store.dispatch('changeSetting', {
|
||||
key: 'showRightPanel',
|
||||
value: val
|
||||
})
|
||||
}
|
||||
},
|
||||
theme: {
|
||||
get() {
|
||||
return this.$store.state.settings.theme
|
||||
}
|
||||
},
|
||||
settingBtn: {
|
||||
get() {
|
||||
return this.$store.state.settings.settingBtn
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
show(value) {
|
||||
if (value && !this.clickNotClose) {
|
||||
this.addEventClick()
|
||||
}
|
||||
if (value) {
|
||||
addClass(document.body, 'showRightPanel')
|
||||
} else {
|
||||
removeClass(document.body, 'showRightPanel')
|
||||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.insertToBody()
|
||||
},
|
||||
beforeDestroy() {
|
||||
const elx = this.$refs.rightPanel
|
||||
elx.remove()
|
||||
},
|
||||
methods: {
|
||||
addEventClick() {
|
||||
window.addEventListener('click', this.closeSidebar)
|
||||
},
|
||||
closeSidebar(evt) {
|
||||
const parent = evt.target.closest('.rightPanel')
|
||||
if (!parent) {
|
||||
this.show = false
|
||||
window.removeEventListener('click', this.closeSidebar)
|
||||
}
|
||||
},
|
||||
insertToBody() {
|
||||
const elx = this.$refs.rightPanel
|
||||
const body = document.querySelector('body')
|
||||
body.insertBefore(elx, body.firstChild)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.showRightPanel {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
width: calc(100% - 15px);
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.rightPanel-background {
|
||||
opacity: 0;
|
||||
transition: opacity .3s cubic-bezier(.7, .3, .1, 1);
|
||||
background: rgba(0, 0, 0, .2);
|
||||
width: 0;
|
||||
height: 0;
|
||||
top: 0;
|
||||
left: 0;
|
||||
position: fixed;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.rightPanel {
|
||||
background: #fff;
|
||||
position: fixed;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
max-width: 260px;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, .05);
|
||||
transition: all .25s cubic-bezier(.7, .3, .1, 1);
|
||||
transform: translate(100%);
|
||||
z-index: 40000;
|
||||
left: auto;
|
||||
right: 0px;
|
||||
}
|
||||
|
||||
.show {
|
||||
transition: all .3s cubic-bezier(.7, .3, .1, 1);
|
||||
|
||||
.rightPanel-background {
|
||||
z-index: 20000;
|
||||
opacity: 1;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.rightPanel {
|
||||
transform: translate(0);
|
||||
}
|
||||
}
|
||||
|
||||
.handle-button {
|
||||
position: absolute;
|
||||
left: -48px;
|
||||
border-radius: 6px 0 0 6px !important;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
pointer-events: auto;
|
||||
z-index: 0;
|
||||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
font-size: 24px;
|
||||
text-align: center;
|
||||
color: #fff;
|
||||
line-height: 48px;
|
||||
|
||||
i {
|
||||
font-size: 24px;
|
||||
line-height: 48px;
|
||||
}
|
||||
}
|
||||
</style>
|
78
src/components/Screenfull/index.vue
Normal file
@ -0,0 +1,78 @@
|
||||
<template>
|
||||
<div>
|
||||
<svg
|
||||
t="1508738709248"
|
||||
class="screenfull-svg"
|
||||
viewBox="0 0 1024 1024"
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
p-id="2069"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
width="32"
|
||||
height="32"
|
||||
@click="click">
|
||||
<path
|
||||
d="M333.493443 428.647617 428.322206 333.832158 262.572184 168.045297 366.707916 64.444754 64.09683 64.444754 63.853283 366.570793 167.283957 262.460644Z"
|
||||
p-id="2070"/>
|
||||
<path
|
||||
d="M854.845439 760.133334 688.61037 593.95864 593.805144 688.764889 759.554142 854.56096 655.44604 958.161503 958.055079 958.161503 958.274066 656.035464Z"
|
||||
p-id="2071"/>
|
||||
<path
|
||||
d="M688.535669 428.550403 854.31025 262.801405 957.935352 366.921787 957.935352 64.34754 655.809313 64.081481 759.919463 167.535691 593.70793 333.731874Z"
|
||||
p-id="2072"/>
|
||||
<path
|
||||
d="M333.590658 594.033341 167.8171 759.804852 64.218604 655.67219 64.218604 958.270996 366.342596 958.502263 262.234493 855.071589 428.421466 688.86108Z"
|
||||
p-id="2073"/>
|
||||
</svg>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import screenfull from 'screenfull'
|
||||
|
||||
export default {
|
||||
name: 'Screenfull',
|
||||
props: {
|
||||
width: {
|
||||
type: Number,
|
||||
default: 22
|
||||
},
|
||||
height: {
|
||||
type: Number,
|
||||
default: 22
|
||||
},
|
||||
fill: {
|
||||
type: String,
|
||||
default: '#48576a'
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isFullscreen: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
click() {
|
||||
if (!screenfull.enabled) {
|
||||
this.$message({
|
||||
message: 'you browser can not work',
|
||||
type: 'warning'
|
||||
})
|
||||
return false
|
||||
}
|
||||
screenfull.toggle()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.screenfull-svg {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
fill: #5a5e66;;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
vertical-align: 10px;
|
||||
}
|
||||
</style>
|
92
src/components/ScrollPane/index.vue
Normal file
@ -0,0 +1,92 @@
|
||||
<template>
|
||||
<el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.native.prevent="handleScroll">
|
||||
<slot/>
|
||||
</el-scrollbar>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const tagAndTagSpacing = 4 // tagAndTagSpacing
|
||||
|
||||
export default {
|
||||
name: 'ScrollPane',
|
||||
data() {
|
||||
return {
|
||||
left: 0
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
handleScroll(e) {
|
||||
const eventDelta = e.wheelDelta || -e.deltaY * 40
|
||||
const $scrollWrapper = this.$refs.scrollContainer.$refs.wrap
|
||||
$scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
|
||||
},
|
||||
moveToTarget(currentTag) {
|
||||
const $container = this.$refs.scrollContainer.$el
|
||||
const $containerWidth = $container.offsetWidth
|
||||
const $scrollWrapper = this.$refs.scrollContainer.$refs.wrap
|
||||
const tagList = this.$parent.$refs.tag
|
||||
|
||||
let firstTag = null
|
||||
let lastTag = null
|
||||
let prevTag = null
|
||||
let nextTag = null
|
||||
|
||||
// find first tag and last tag
|
||||
if (tagList.length > 0) {
|
||||
firstTag = tagList[0]
|
||||
lastTag = tagList[tagList.length - 1]
|
||||
}
|
||||
|
||||
// find preTag and nextTag
|
||||
for (let i = 0; i < tagList.length; i++) {
|
||||
if (tagList[i] === currentTag) {
|
||||
if (i === 0) {
|
||||
nextTag = tagList[i].length > 1 && tagList[i + 1]
|
||||
} else if (i === tagList.length - 1) {
|
||||
prevTag = tagList[i].length > 1 && tagList[i - 1]
|
||||
} else {
|
||||
prevTag = tagList[i - 1]
|
||||
nextTag = tagList[i + 1]
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if (firstTag === currentTag) {
|
||||
$scrollWrapper.scrollLeft = 0
|
||||
} else if (lastTag === currentTag) {
|
||||
$scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth
|
||||
} else {
|
||||
// the tag's offsetLeft after of nextTag
|
||||
const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing
|
||||
|
||||
// the tag's offsetLeft before of prevTag
|
||||
const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing
|
||||
|
||||
if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
|
||||
$scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
|
||||
} else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
|
||||
$scrollWrapper.scrollLeft = beforePrevTagOffsetLeft
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style rel="stylesheet/scss" lang="scss" scoped>
|
||||
.scroll-container {
|
||||
white-space: nowrap;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
width: 100%;
|
||||
/deep/ {
|
||||
.el-scrollbar__bar {
|
||||
bottom: 0px;
|
||||
}
|
||||
.el-scrollbar__wrap {
|
||||
height: 49px;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
43
src/components/SvgIcon/index.vue
Normal file
@ -0,0 +1,43 @@
|
||||
<template>
|
||||
<svg :class="svgClass" aria-hidden="true">
|
||||
<use :xlink:href="iconName"/>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'SvgIcon',
|
||||
props: {
|
||||
iconClass: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
className: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
iconName() {
|
||||
return `#icon-${this.iconClass}`
|
||||
},
|
||||
svgClass() {
|
||||
if (this.className) {
|
||||
return 'svg-icon ' + this.className
|
||||
} else {
|
||||
return 'svg-icon'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.svg-icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
vertical-align: -0.15em;
|
||||
fill: currentColor;
|
||||
overflow: hidden;
|
||||
}
|
||||
</style>
|
113
src/components/TextHoverEffect/Mallki.vue
Normal file
@ -0,0 +1,113 @@
|
||||
<template>
|
||||
<a :class="className" class="link--mallki" href="#">
|
||||
{{ text }}
|
||||
<span :data-letters="text"/>
|
||||
<span :data-letters="text"/>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
className: {
|
||||
type: String,
|
||||
default: ''
|
||||
},
|
||||
text: {
|
||||
type: String,
|
||||
default: 'vue-element-admin'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
/* Mallki */
|
||||
|
||||
.link--mallki {
|
||||
font-weight: 800;
|
||||
color: #4dd9d5;
|
||||
font-family: 'Dosis', sans-serif;
|
||||
-webkit-transition: color 0.5s 0.25s;
|
||||
transition: color 0.5s 0.25s;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
line-height: 1;
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.link--mallki:hover {
|
||||
-webkit-transition: none;
|
||||
transition: none;
|
||||
color: transparent;
|
||||
}
|
||||
|
||||
.link--mallki::before {
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
margin: -3px 0 0 0;
|
||||
background: #3888fa;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
-webkit-transform: translate3d(-100%, 0, 0);
|
||||
transform: translate3d(-100%, 0, 0);
|
||||
-webkit-transition: -webkit-transform 0.4s;
|
||||
transition: transform 0.4s;
|
||||
-webkit-transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1);
|
||||
transition-timing-function: cubic-bezier(0.7, 0, 0.3, 1);
|
||||
}
|
||||
|
||||
.link--mallki:hover::before {
|
||||
-webkit-transform: translate3d(100%, 0, 0);
|
||||
transform: translate3d(100%, 0, 0);
|
||||
}
|
||||
|
||||
.link--mallki span {
|
||||
position: absolute;
|
||||
height: 50%;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.link--mallki span::before {
|
||||
content: attr(data-letters);
|
||||
color: red;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
color: #3888fa;
|
||||
-webkit-transition: -webkit-transform 0.5s;
|
||||
transition: transform 0.5s;
|
||||
}
|
||||
|
||||
.link--mallki span:nth-child(2) {
|
||||
top: 50%;
|
||||
}
|
||||
|
||||
.link--mallki span:first-child::before {
|
||||
top: 0;
|
||||
-webkit-transform: translate3d(0, 100%, 0);
|
||||
transform: translate3d(0, 100%, 0);
|
||||
}
|
||||
|
||||
.link--mallki span:nth-child(2)::before {
|
||||
bottom: 0;
|
||||
-webkit-transform: translate3d(0, -100%, 0);
|
||||
transform: translate3d(0, -100%, 0);
|
||||
}
|
||||
|
||||
.link--mallki:hover span::before {
|
||||
-webkit-transition-delay: 0.3s;
|
||||
transition-delay: 0.3s;
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
transform: translate3d(0, 0, 0);
|
||||
-webkit-transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
|
||||
transition-timing-function: cubic-bezier(0.2, 1, 0.3, 1);
|
||||
}
|
||||
</style>
|
29
src/components/TreeTable/eval.js
Normal file
@ -0,0 +1,29 @@
|
||||
/**
|
||||
* @Author: jianglei
|
||||
* @Date: 2017-10-12 12:06:49
|
||||
*/
|
||||
'use strict'
|
||||
import Vue from 'vue'
|
||||
export default function treeToArray(data, expandAll, parent = null, level = null) {
|
||||
let tmp = []
|
||||
Array.from(data).forEach(function(record) {
|
||||
if (record._expanded === undefined) {
|
||||
Vue.set(record, '_expanded', expandAll)
|
||||
}
|
||||
let _level = 1
|
||||
if (level !== undefined && level !== null) {
|
||||
_level = level + 1
|
||||
}
|
||||
Vue.set(record, '_level', _level)
|
||||
// 如果有父元素
|
||||
if (parent) {
|
||||
Vue.set(record, 'parent', parent)
|
||||
}
|
||||
tmp.push(record)
|
||||
if (record.children && record.children.length > 0) {
|
||||
const children = treeToArray(record.children, expandAll, record, _level)
|
||||
tmp = tmp.concat(children)
|
||||
}
|
||||
})
|
||||
return tmp
|
||||
}
|
127
src/components/TreeTable/index.vue
Normal file
@ -0,0 +1,127 @@
|
||||
<template>
|
||||
<el-table :data="formatData" :row-style="showRow" v-bind="$attrs">
|
||||
<el-table-column v-if="columns.length===0" width="150">
|
||||
<template slot-scope="scope">
|
||||
<span v-for="space in scope.row._level" :key="space" class="ms-tree-space"/>
|
||||
<span v-if="iconShow(0,scope.row)" class="tree-ctrl" @click="toggleExpanded(scope.$index)">
|
||||
<i v-if="!scope.row._expanded" class="el-icon-plus"/>
|
||||
<i v-else class="el-icon-minus"/>
|
||||
</span>
|
||||
{{ scope.$index }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column v-for="(column, index) in columns" v-else :key="column.value" :label="column.text" :width="column.width">
|
||||
<template slot-scope="scope">
|
||||
<!-- Todo -->
|
||||
<!-- eslint-disable-next-line vue/no-confusing-v-for-v-if -->
|
||||
<span v-for="space in scope.row._level" v-if="index === 0" :key="space" class="ms-tree-space"/>
|
||||
<span v-if="iconShow(index,scope.row)" class="tree-ctrl" @click="toggleExpanded(scope.$index)">
|
||||
<i v-if="!scope.row._expanded" class="el-icon-plus"/>
|
||||
<i v-else class="el-icon-minus"/>
|
||||
</span>
|
||||
{{ scope.row[column.value] }}
|
||||
</template>
|
||||
</el-table-column>
|
||||
<slot/>
|
||||
</el-table>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/**
|
||||
Auth: Lei.j1ang
|
||||
Created: 2018/1/19-13:59
|
||||
*/
|
||||
import treeToArray from './eval'
|
||||
export default {
|
||||
name: 'TreeTable',
|
||||
props: {
|
||||
/* eslint-disable */
|
||||
data: {
|
||||
type: [Array, Object],
|
||||
required: true
|
||||
},
|
||||
columns: {
|
||||
type: Array,
|
||||
default: () => []
|
||||
},
|
||||
evalFunc: Function,
|
||||
evalArgs: Array,
|
||||
expandAll: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
// 格式化数据源
|
||||
formatData: function() {
|
||||
let tmp
|
||||
if (!Array.isArray(this.data)) {
|
||||
tmp = [this.data]
|
||||
} else {
|
||||
tmp = this.data
|
||||
}
|
||||
const func = this.evalFunc || treeToArray
|
||||
const args = this.evalArgs ? Array.concat([tmp, this.expandAll], this.evalArgs) : [tmp, this.expandAll]
|
||||
return func.apply(null, args)
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
showRow: function(row) {
|
||||
const show = (row.row.parent ? (row.row.parent._expanded && row.row.parent._show) : true)
|
||||
row.row._show = show
|
||||
return show ? 'animation:treeTableShow 1s;-webkit-animation:treeTableShow 1s;' : 'display:none;'
|
||||
},
|
||||
// 切换下级是否展开
|
||||
toggleExpanded: function(trIndex) {
|
||||
const record = this.formatData[trIndex]
|
||||
record._expanded = !record._expanded
|
||||
},
|
||||
// 图标显示
|
||||
iconShow(index, record) {
|
||||
return (index === 0 && record.children && record.children.length > 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style rel="stylesheet/css">
|
||||
@keyframes treeTableShow {
|
||||
from {opacity: 0;}
|
||||
to {opacity: 1;}
|
||||
}
|
||||
@-webkit-keyframes treeTableShow {
|
||||
from {opacity: 0;}
|
||||
to {opacity: 1;}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" rel="stylesheet/scss" scoped>
|
||||
$color-blue: #2196F3;
|
||||
$space-width: 18px;
|
||||
.ms-tree-space {
|
||||
position: relative;
|
||||
top: 1px;
|
||||
display: inline-block;
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
width: $space-width;
|
||||
height: 14px;
|
||||
&::before {
|
||||
content: ""
|
||||
}
|
||||
}
|
||||
.processContainer{
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
table td {
|
||||
line-height: 26px;
|
||||
}
|
||||
|
||||
.tree-ctrl{
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
color: $color-blue;
|
||||
margin-left: -$space-width;
|
||||
}
|
||||
</style>
|
89
src/components/TreeTable/readme.md
Normal file
@ -0,0 +1,89 @@
|
||||
## 写在前面
|
||||
此组件仅提供一个创建TreeTable的解决思路
|
||||
|
||||
## prop说明
|
||||
#### *data*
|
||||
**必填**
|
||||
|
||||
原始数据,要求是一个数组或者对象
|
||||
```javascript
|
||||
[{
|
||||
key1: value1,
|
||||
key2: value2,
|
||||
children: [{
|
||||
key1: value1
|
||||
},
|
||||
{
|
||||
key1: value1
|
||||
}]
|
||||
},
|
||||
{
|
||||
key1: value1
|
||||
}]
|
||||
```
|
||||
或者
|
||||
```javascript
|
||||
{
|
||||
key1: value1,
|
||||
key2: value2,
|
||||
children: [{
|
||||
key1: value1
|
||||
},
|
||||
{
|
||||
key1: value1
|
||||
}]
|
||||
}
|
||||
```
|
||||
|
||||
#### columns
|
||||
列属性,要求是一个数组
|
||||
|
||||
1. text: 显示在表头的文字
|
||||
2. value: 对应data的key。treeTable将显示相应的value
|
||||
3. width: 每列的宽度,为一个数字(可选)
|
||||
|
||||
如果你想要每个字段都有自定义的样式或者嵌套其他组件,columns可不提供,直接像在el-table一样写即可,如果没有自定义内容,提供columns将更加的便捷方便
|
||||
|
||||
如果你有几个字段是需要自定义的,几个不需要,那么可以将不需要自定义的字段放入columns,将需要自定义的内容放入到slot中,详情见后文
|
||||
```javascript
|
||||
[{
|
||||
value:string,
|
||||
text:string,
|
||||
width:number
|
||||
},{
|
||||
value:string,
|
||||
text:string,
|
||||
width:number
|
||||
}]
|
||||
```
|
||||
|
||||
#### expandAll
|
||||
是否默认全部展开,boolean值,默认为false
|
||||
|
||||
#### evalFunc
|
||||
解析函数,function,非必须
|
||||
|
||||
如果不提供,将使用默认的[evalFunc](./eval.js)
|
||||
|
||||
如果提供了evalFunc,那么会用提供的evalFunc去解析data,并返回treeTable渲染所需要的值。如何编写一个evalFunc,请参考[*eval.js*](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/components/TreeTable/eval.js)或[*customEval.js*](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/table/treeTable/customEval.js)
|
||||
|
||||
#### evalArgs
|
||||
解析函数的参数,是一个数组
|
||||
|
||||
**请注意,自定义的解析函数参数第一个为this.data,第二个参数为, this.expandAll,你不需要在evalArgs填写。一定记住,这两个参数是强制性的,并且位置不可颠倒** *this.data为需要解析的数据,this.expandAll为是否默认展开*
|
||||
|
||||
如你的解析函数需要的参数为`(this.data, this.expandAll,1,2,3,4)`,那么你只需要将`[1,2,3,4]`赋值给`evalArgs`就可以了
|
||||
|
||||
如果你的解析函数参数只有`(this.data, this.expandAll)`,那么就可以不用填写evalArgs了
|
||||
|
||||
具体可参考[*customEval.js*](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/table/treeTable/customEval.js)的函数参数和[customTreeTable](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/table/treeTable/customTreeTable.vue)的`evalArgs`属性值
|
||||
|
||||
## slot
|
||||
这是一个自定义列的插槽。
|
||||
|
||||
默认情况下,treeTable只有一行行展示数据的功能。但是一般情况下,我们会要给行加上一个操作按钮或者根据当行数据展示不同的样式,这时我们就需要自定义列了。请参考[customTreeTable](https://github.com/PanJiaChen/vue-element-admin/blob/master/src/views/table/treeTable/customTreeTable.vue),[实例效果](https://panjiachen.github.io/vue-element-admin/#/table/tree-table)
|
||||
|
||||
`slot`和`columns属性`可同时存在,columns里面的数据列会在slot自定义列的左边展示
|
||||
|
||||
## 其他
|
||||
如果有其他的需求,请参考[el-table](http://element-cn.eleme.io/#/en-US/component/table)的api自行修改index.vue
|
81
src/components/YamlEdit/index.vue
Normal file
@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<div class="json-editor">
|
||||
<textarea ref="textarea"/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import CodeMirror from 'codemirror'
|
||||
import 'codemirror/lib/codemirror.css'
|
||||
// 替换主题这里需修改名称
|
||||
import 'codemirror/theme/idea.css'
|
||||
require('codemirror/mode/yaml/yaml.js')
|
||||
export default {
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
height: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
editor: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
value(value) {
|
||||
const editorValue = this.editor.getValue()
|
||||
if (value !== editorValue) {
|
||||
this.editor.setValue(this.value)
|
||||
}
|
||||
},
|
||||
height(value) {
|
||||
this.editor.setSize('auto', this.height)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.editor = CodeMirror.fromTextArea(this.$refs.textarea, {
|
||||
mode: 'text/x-yaml',
|
||||
lineNumbers: true,
|
||||
lint: true,
|
||||
lineWrapping: true,
|
||||
tabSize: 2,
|
||||
cursorHeight: 0.9,
|
||||
// 替换主题这里需修改名称
|
||||
theme: 'idea'
|
||||
})
|
||||
this.editor.setSize('auto', this.height)
|
||||
this.editor.setValue(this.value)
|
||||
this.editor.on('change', cm => {
|
||||
this.$emit('changed', cm.getValue())
|
||||
this.$emit('input', cm.getValue())
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
getValue() {
|
||||
return this.editor.getValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.json-editor{
|
||||
height: 100%;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.json-editor >>> .CodeMirror {
|
||||
font-size: 13px;
|
||||
overflow-y:auto;
|
||||
font-weight:normal
|
||||
}
|
||||
.json-editor >>> .CodeMirror-scroll{
|
||||
}
|
||||
.json-editor >>> .cm-s-rubyblue span.cm-string {
|
||||
color: #F08047;
|
||||
}
|
||||
</style>
|
30
src/components/iframe/index.vue
Normal file
@ -0,0 +1,30 @@
|
||||
<template>
|
||||
<div v-loading="loading" :style="'height:'+ height">
|
||||
<iframe :src="src" frameborder="no" style="width: 100%;height: 100%" scrolling="auto"/>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
src: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
height: document.documentElement.clientHeight - 94.5 + 'px;',
|
||||
loading: true
|
||||
}
|
||||
},
|
||||
mounted: function() {
|
||||
setTimeout(() => {
|
||||
this.loading = false
|
||||
}, 230)
|
||||
const that = this
|
||||
window.onresize = function temp() {
|
||||
that.height = document.documentElement.clientHeight - 94.5 + 'px;'
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
94
src/components/mul-pic-upload/index.vue
Normal file
@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-upload
|
||||
:action="qiNiuUploadApi"
|
||||
:headers="headers"
|
||||
list-type="picture-card"
|
||||
:on-preview="handlePictureCardPreview"
|
||||
:on-remove="handleRemove"
|
||||
:on-success="handleUploadSuccess"
|
||||
:file-list="imageList"
|
||||
:before-upload="beforeAvatarUpload">
|
||||
<i class="el-icon-plus"></i>
|
||||
</el-upload>
|
||||
<el-dialog :visible.sync="dialogVisible">
|
||||
<img width="100%" :src="dialogImageUrl" alt="">
|
||||
</el-dialog>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getToken } from '@/utils/auth'
|
||||
import { mapGetters } from 'vuex'
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
dialogImageUrl: '',
|
||||
dialogVisible: false,
|
||||
resourcesUrl: '',
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + getToken()
|
||||
}
|
||||
}
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
default: '',
|
||||
type: String
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'qiNiuUploadApi'
|
||||
]),
|
||||
imageList () {
|
||||
let res = []
|
||||
if (this.value) {
|
||||
let imageArray = this.value.split(',')
|
||||
for (let i = 0; i < imageArray.length; i++) {
|
||||
res.push({url: this.resourcesUrl + imageArray[i], response: imageArray[i]})
|
||||
}
|
||||
}
|
||||
this.$emit('input', this.value)
|
||||
return res
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 图片上传
|
||||
handleUploadSuccess (response, file, fileList) {
|
||||
console.log(file);
|
||||
console.log(fileList)
|
||||
let pics = fileList.map(file => {
|
||||
if((typeof file.response) == 'object'){
|
||||
return file.response.data[0]
|
||||
}else{
|
||||
return file.response
|
||||
}
|
||||
}).join(',')
|
||||
console.log(pics)
|
||||
this.$emit('input', pics)
|
||||
},
|
||||
// 限制图片上传大小
|
||||
beforeAvatarUpload (file) {
|
||||
const isLt2M = file.size / 1024 / 1024 < 2
|
||||
if (!isLt2M) {
|
||||
this.$message.error('上传头像图片大小不能超过 2MB!')
|
||||
}
|
||||
return isLt2M
|
||||
},
|
||||
handleRemove (file, fileList) {
|
||||
let pics = fileList.map(file => {
|
||||
return file.response
|
||||
}).join(',')
|
||||
this.$emit('input', pics)
|
||||
},
|
||||
handlePictureCardPreview (file) {
|
||||
this.dialogImageUrl = file.url
|
||||
this.dialogVisible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
</style>
|
13
src/components/permission/index.js
Normal file
@ -0,0 +1,13 @@
|
||||
import permission from './permission'
|
||||
|
||||
const install = function(Vue) {
|
||||
Vue.directive('permission', permission)
|
||||
}
|
||||
|
||||
if (window.Vue) {
|
||||
window['permission'] = permission
|
||||
Vue.use(install); // eslint-disable-line
|
||||
}
|
||||
|
||||
permission.install = install
|
||||
export default permission
|
22
src/components/permission/permission.js
Normal file
@ -0,0 +1,22 @@
|
||||
import store from '@/store'
|
||||
|
||||
export default {
|
||||
inserted(el, binding, vnode) {
|
||||
const { value } = binding
|
||||
const roles = store.getters && store.getters.roles
|
||||
|
||||
if (value && value instanceof Array && value.length > 0) {
|
||||
const permissionRoles = value
|
||||
|
||||
const hasPermission = roles.some(role => {
|
||||
return permissionRoles.includes(role)
|
||||
})
|
||||
|
||||
if (!hasPermission) {
|
||||
el.parentNode && el.parentNode.removeChild(el)
|
||||
}
|
||||
} else {
|
||||
throw new Error(`need roles! Like v-permission="['admin','editor']"`)
|
||||
}
|
||||
}
|
||||
}
|
82
src/components/pic-upload-two/index.vue
Normal file
@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-upload
|
||||
class="pic-uploader-component"
|
||||
:action="qiNiuUploadApi"
|
||||
:headers="headers"
|
||||
:show-file-list="false"
|
||||
:on-success="handleUploadSuccess"
|
||||
:before-upload="beforeAvatarUpload">
|
||||
<img v-if="value" :src="resourcesUrl + value" class="pic">
|
||||
<i v-else class="el-icon-plus pic-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getToken } from '@/utils/auth'
|
||||
import { mapGetters } from 'vuex'
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
resourcesUrl: '',
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + getToken()
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'qiNiuUploadApi'
|
||||
])
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
default: '',
|
||||
type: String
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 图片上传
|
||||
handleUploadSuccess(response, file, fileList) {
|
||||
console.log(file)
|
||||
this.$emit('input', file.response.data[0])
|
||||
},
|
||||
// 限制图片上传大小
|
||||
beforeAvatarUpload(file) {
|
||||
const isLt2M = file.size / 1024 / 1024 < 2
|
||||
if (!isLt2M) {
|
||||
this.$message.error('上传头像图片大小不能超过 2MB!')
|
||||
}
|
||||
return isLt2M
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.pic-uploader-component .el-upload {
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
.pic-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
//line-height: 178px;
|
||||
text-align: center;
|
||||
}
|
||||
.pic {
|
||||
width: 100%;
|
||||
height: 40px;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.pic-uploader-component .el-upload:hover {
|
||||
border-color: #409EFF;
|
||||
}
|
||||
|
||||
</style>
|
82
src/components/pic-upload/index.vue
Normal file
@ -0,0 +1,82 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-upload
|
||||
class="pic-uploader-component"
|
||||
:action="qiNiuUploadApi"
|
||||
:headers="headers"
|
||||
:show-file-list="false"
|
||||
:on-success="handleUploadSuccess"
|
||||
:before-upload="beforeAvatarUpload">
|
||||
<img v-if="value" :src="resourcesUrl + value" class="pic">
|
||||
<i v-else class="el-icon-plus pic-uploader-icon"></i>
|
||||
</el-upload>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getToken } from '@/utils/auth'
|
||||
import { mapGetters } from 'vuex'
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
resourcesUrl: '',
|
||||
headers: {
|
||||
'Authorization': 'Bearer ' + getToken()
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapGetters([
|
||||
'qiNiuUploadApi'
|
||||
])
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
default: '',
|
||||
type: String
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
// 图片上传
|
||||
handleUploadSuccess(response, file, fileList) {
|
||||
console.log(file)
|
||||
this.$emit('input', file.response.data[0])
|
||||
},
|
||||
// 限制图片上传大小
|
||||
beforeAvatarUpload(file) {
|
||||
const isLt2M = file.size / 1024 / 1024 < 2
|
||||
if (!isLt2M) {
|
||||
this.$message.error('上传头像图片大小不能超过 2MB!')
|
||||
}
|
||||
return isLt2M
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.pic-uploader-component .el-upload {
|
||||
border: 1px dashed #d9d9d9;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
.pic-uploader-icon {
|
||||
font-size: 28px;
|
||||
color: #8c939d;
|
||||
width: 178px;
|
||||
height: 178px;
|
||||
line-height: 178px;
|
||||
text-align: center;
|
||||
}
|
||||
.pic {
|
||||
width: 178px;
|
||||
height: 178px;
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
.pic-uploader-component .el-upload:hover {
|
||||
border-color: #409EFF;
|
||||
}
|
||||
|
||||
</style>
|
82
src/components/pic-upload2/index.vue
Normal file
@ -0,0 +1,82 @@
|
||||
<!--<template>-->
|
||||
<!--<div>-->
|
||||
<!--<el-upload-->
|
||||
<!--class="pic-uploader-component"-->
|
||||
<!--:action="imagesUploadApi"-->
|
||||
<!--:headers="headers"-->
|
||||
<!--:show-file-list="false"-->
|
||||
<!--:on-success="handleUploadSuccess"-->
|
||||
<!--:before-upload="beforeAvatarUpload">-->
|
||||
<!--<img v-if="value" :src="resourcesUrl + value" class="pic">-->
|
||||
<!--<i v-else class="el-icon-plus pic-uploader-icon"></i>-->
|
||||
<!--</el-upload>-->
|
||||
<!--</div>-->
|
||||
<!--</template>-->
|
||||
|
||||
<!--<script>-->
|
||||
<!--import { getToken } from '@/utils/auth'-->
|
||||
<!--import { mapGetters } from 'vuex'-->
|
||||
<!--export default {-->
|
||||
<!--data () {-->
|
||||
<!--return {-->
|
||||
<!--resourcesUrl: '',-->
|
||||
<!--headers: {-->
|
||||
<!--'Authorization': 'Bearer ' + getToken()-->
|
||||
<!--}-->
|
||||
<!--}-->
|
||||
<!--},-->
|
||||
<!--computed: {-->
|
||||
<!--...mapGetters([-->
|
||||
<!--'imagesUploadApi'-->
|
||||
<!--])-->
|
||||
<!--},-->
|
||||
<!--props: {-->
|
||||
<!--value: {-->
|
||||
<!--default: '',-->
|
||||
<!--type: String-->
|
||||
<!--}-->
|
||||
<!--},-->
|
||||
<!--methods: {-->
|
||||
<!--// 图片上传-->
|
||||
<!--handleUploadSuccess(response, file, fileList) {-->
|
||||
<!--console.log(file)-->
|
||||
<!--this.$emit('input', file.response.data[0])-->
|
||||
<!--},-->
|
||||
<!--// 限制图片上传大小-->
|
||||
<!--beforeAvatarUpload(file) {-->
|
||||
<!--const isLt2M = file.size / 1024 / 1024 < 2-->
|
||||
<!--if (!isLt2M) {-->
|
||||
<!--this.$message.error('上传头像图片大小不能超过 2MB!')-->
|
||||
<!--}-->
|
||||
<!--return isLt2M-->
|
||||
<!--}-->
|
||||
<!--}-->
|
||||
<!--}-->
|
||||
<!--</script>-->
|
||||
|
||||
<!--<style lang="scss">-->
|
||||
<!--.pic-uploader-component .el-upload {-->
|
||||
<!--border: 1px dashed #d9d9d9;-->
|
||||
<!--border-radius: 6px;-->
|
||||
<!--cursor: pointer;-->
|
||||
<!--position: relative;-->
|
||||
<!--overflow: hidden;-->
|
||||
<!--.pic-uploader-icon {-->
|
||||
<!--font-size: 28px;-->
|
||||
<!--color: #8c939d;-->
|
||||
<!--width: 100%;-->
|
||||
<!--height: 40px;-->
|
||||
<!--//line-height: 178px;-->
|
||||
<!--text-align: center;-->
|
||||
<!--}-->
|
||||
<!--.pic {-->
|
||||
<!--width: 100%;-->
|
||||
<!--height: 40px;-->
|
||||
<!--display: block;-->
|
||||
<!--}-->
|
||||
<!--}-->
|
||||
<!--.pic-uploader-component .el-upload:hover {-->
|
||||
<!--border-color: #409EFF;-->
|
||||
<!--}-->
|
||||
|
||||
<!--</style>-->
|
65
src/config/index.js
Normal file
@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @description 系统全局配置
|
||||
*/
|
||||
export default {
|
||||
/**
|
||||
* @description 记住密码状态下的token在Cookie中存储的天数,默认1天
|
||||
*/
|
||||
tokenCookieExpires: 1,
|
||||
/**
|
||||
* @description 记住密码状态下的密码在Cookie中存储的天数,默认1天
|
||||
*/
|
||||
passCookieExpires: 1,
|
||||
/**
|
||||
* @description 此处修改网站名称
|
||||
*/
|
||||
webName: 'Yshop',
|
||||
/**
|
||||
* @description 是否只保持一个子菜单的展开
|
||||
*/
|
||||
uniqueOpened: true,
|
||||
/**
|
||||
* @description token key
|
||||
*/
|
||||
TokenKey: 'Yshop-TOEKN',
|
||||
|
||||
/**
|
||||
* @description 请求超时时间,毫秒(默认2分钟)
|
||||
*/
|
||||
timeout: 1200000,
|
||||
|
||||
/**
|
||||
* @description 是否显示 tagsView
|
||||
*/
|
||||
tagsView: true,
|
||||
|
||||
/**
|
||||
* @description 固定头部
|
||||
*/
|
||||
fixedHeader: true,
|
||||
|
||||
/**
|
||||
* @description 是否显示logo
|
||||
*/
|
||||
sidebarLogo: true,
|
||||
|
||||
/**
|
||||
* 是否显示设置的悬浮按钮
|
||||
*/
|
||||
settingBtn: false,
|
||||
|
||||
/**
|
||||
* 是否显示设置的底部信息
|
||||
*/
|
||||
showFooter: true,
|
||||
|
||||
/**
|
||||
* 底部文字,支持html语法
|
||||
*/
|
||||
footerTxt: '© 2019 YSHOP <a href="http://www.apache.org/licenses/LICENSE-2.0" target="_blank">Apache License 2.0</a>',
|
||||
|
||||
/**
|
||||
* 备案号
|
||||
*/
|
||||
caseNumber: '豫ICP备17049587号'
|
||||
}
|
9
src/icons/index.js
Normal file
@ -0,0 +1,9 @@
|
||||
import Vue from 'vue'
|
||||
import SvgIcon from '@/components/SvgIcon' // svg组件
|
||||
|
||||
// register globally
|
||||
Vue.component('svg-icon', SvgIcon)
|
||||
|
||||
const requireAll = requireContext => requireContext.keys().map(requireContext)
|
||||
const req = require.context('./svg', false, /\.svg$/)
|
||||
requireAll(req)
|
1
src/icons/svg/Steve-Jobs.svg
Normal file
After Width: | Height: | Size: 6.2 KiB |
2
src/icons/svg/add.svg
Normal file
@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1543748455010" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1208" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: rbicon; src: url("chrome-extension://dipiagiiohfljcicegpgffpbnjmgjcnf/fonts/rbicon.woff2") format("woff2"); font-weight: normal; font-style: normal; }
|
||||
</style></defs><path d="M590.769231 571.076923h324.923077c15.753846 0 29.538462-13.784615 29.538461-29.538461v-59.076924c0-15.753846-13.784615-29.538462-29.538461-29.538461H590.769231c-11.815385 0-19.692308-7.876923-19.692308-19.692308V108.307692c0-15.753846-13.784615-29.538462-29.538461-29.538461h-59.076924c-15.753846 0-29.538462 13.784615-29.538461 29.538461V433.230769c0 11.815385-7.876923 19.692308-19.692308 19.692308H108.307692c-15.753846 0-29.538462 13.784615-29.538461 29.538461v59.076924c0 15.753846 13.784615 29.538462 29.538461 29.538461H433.230769c11.815385 0 19.692308 7.876923 19.692308 19.692308v324.923077c0 15.753846 13.784615 29.538462 29.538461 29.538461h59.076924c15.753846 0 29.538462-13.784615 29.538461-29.538461V590.769231c0-11.815385 7.876923-19.692308 19.692308-19.692308z" p-id="1209"></path></svg>
|
After Width: | Height: | Size: 1.3 KiB |