@ -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 |
|||
@ -0,0 +1,5 @@ |
|||
# just a flag |
|||
ENV = 'development' |
|||
|
|||
# base api |
|||
VUE_APP_BASE_API = 'http://gin.vueadmin.net/api' |
|||
@ -0,0 +1,6 @@ |
|||
# just a flag |
|||
ENV = 'production' |
|||
|
|||
# base api |
|||
VUE_APP_BASE_API = '/api' |
|||
|
|||
@ -0,0 +1,8 @@ |
|||
NODE_ENV = production |
|||
|
|||
# just a flag |
|||
ENV = 'staging' |
|||
|
|||
# base api |
|||
VUE_APP_BASE_API = 'http://new.hxgk.group/api' |
|||
|
|||
@ -0,0 +1,4 @@ |
|||
build/*.js |
|||
src/assets |
|||
public |
|||
dist |
|||
@ -0,0 +1,198 @@ |
|||
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/singleline-html-element-content-newline": "off", |
|||
"vue/multiline-html-element-content-newline":"off", |
|||
"vue/name-property-casing": ["error", "PascalCase"], |
|||
"vue/no-v-html": "off", |
|||
'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': ["error", "always", {"null": "ignore"}], |
|||
'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': 0, |
|||
'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'] |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
.DS_Store |
|||
node_modules/ |
|||
dist/ |
|||
npm-debug.log* |
|||
yarn-debug.log* |
|||
yarn-error.log* |
|||
package-lock.json |
|||
tests/**/coverage/ |
|||
|
|||
# Editor directories and files |
|||
.idea |
|||
.vscode |
|||
*.suo |
|||
*.ntvs* |
|||
*.njsproj |
|||
*.sln |
|||
@ -0,0 +1,5 @@ |
|||
language: node_js |
|||
node_js: 10 |
|||
script: npm run test |
|||
notifications: |
|||
email: false |
|||
@ -0,0 +1,21 @@ |
|||
MIT License |
|||
|
|||
Copyright (c) 2017-present PanJiaChen |
|||
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy |
|||
of this software and associated documentation files (the "Software"), to deal |
|||
in the Software without restriction, including without limitation the rights |
|||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|||
copies of the Software, and to permit persons to whom the Software is |
|||
furnished to do so, subject to the following conditions: |
|||
|
|||
The above copyright notice and this permission notice shall be included in all |
|||
copies or substantial portions of the Software. |
|||
|
|||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|||
SOFTWARE. |
|||
@ -0,0 +1,111 @@ |
|||
# vue-admin-template |
|||
|
|||
> 这是一个极简的 vue admin 管理后台。它只包含了 Element UI & axios & iconfont & permission control & lint,这些搭建后台必要的东西。 |
|||
|
|||
[线上地址](http://panjiachen.github.io/vue-admin-template) |
|||
|
|||
[国内访问](https://panjiachen.gitee.io/vue-admin-template) |
|||
|
|||
目前版本为 `v4.0+` 基于 `vue-cli` 进行构建,若你想使用旧版本,可以切换分支到[tag/3.11.0](https://github.com/PanJiaChen/vue-admin-template/tree/tag/3.11.0),它不依赖 `vue-cli`。 |
|||
|
|||
<p align="center"> |
|||
<b>SPONSORED BY</b> |
|||
</p> |
|||
<p align="center"> |
|||
<a href="https://finclip.com?from=vue_element" title="FinClip" target="_blank"> |
|||
<img height="200px" src="https://gitee.com/panjiachen/gitee-cdn/raw/master/vue%E8%B5%9E%E5%8A%A9.png" title="FinClip"> |
|||
</a> |
|||
</p> |
|||
|
|||
## Extra |
|||
|
|||
如果你想要根据用户角色来动态生成侧边栏和 router,你可以使用该分支[permission-control](https://github.com/PanJiaChen/vue-admin-template/tree/permission-control) |
|||
|
|||
## 相关项目 |
|||
|
|||
- [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) |
|||
|
|||
- [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin) |
|||
|
|||
- [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) |
|||
|
|||
- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312) |
|||
|
|||
写了一个系列的教程配套文章,如何从零构建后一个完整的后台项目: |
|||
|
|||
- [手摸手,带你用 vue 撸后台 系列一(基础篇)](https://juejin.im/post/59097cd7a22b9d0065fb61d2) |
|||
- [手摸手,带你用 vue 撸后台 系列二(登录权限篇)](https://juejin.im/post/591aa14f570c35006961acac) |
|||
- [手摸手,带你用 vue 撸后台 系列三 (实战篇)](https://juejin.im/post/593121aa0ce4630057f70d35) |
|||
- [手摸手,带你用 vue 撸后台 系列四(vueAdmin 一个极简的后台基础模板,专门针对本项目的文章,算作是一篇文档)](https://juejin.im/post/595b4d776fb9a06bbe7dba56) |
|||
- [手摸手,带你封装一个 vue component](https://segmentfault.com/a/1190000009090836) |
|||
|
|||
## Build Setup |
|||
|
|||
```bash |
|||
# 克隆项目 |
|||
git clone https://github.com/PanJiaChen/vue-admin-template.git |
|||
|
|||
# 进入项目目录 |
|||
cd vue-admin-template |
|||
|
|||
# 安装依赖 |
|||
npm install |
|||
|
|||
# 建议不要直接使用 cnpm 安装以来,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题 |
|||
npm install --registry=https://registry.npm.taobao.org |
|||
|
|||
# 启动服务 |
|||
npm run dev |
|||
``` |
|||
|
|||
浏览器访问 [http://localhost:9528](http://localhost:9528) |
|||
|
|||
## 发布 |
|||
|
|||
```bash |
|||
# 构建测试环境 |
|||
npm run build:stage |
|||
|
|||
# 构建生产环境 |
|||
npm run build:prod |
|||
``` |
|||
|
|||
## 其它 |
|||
|
|||
```bash |
|||
# 预览发布环境效果 |
|||
npm run preview |
|||
|
|||
# 预览发布环境效果 + 静态资源分析 |
|||
npm run preview -- --report |
|||
|
|||
# 代码格式检查 |
|||
npm run lint |
|||
|
|||
# 代码格式检查并自动修复 |
|||
npm run lint -- --fix |
|||
``` |
|||
|
|||
更多信息请参考 [使用文档](https://panjiachen.github.io/vue-element-admin-site/zh/) |
|||
|
|||
## 购买贴纸 |
|||
|
|||
你也可以通过 购买[官方授权的贴纸](https://smallsticker.com/product/vue-element-admin) 的方式来支持 vue-element-admin - 每售出一张贴纸,我们将获得 2 元的捐赠。 |
|||
|
|||
## Demo |
|||
|
|||
 |
|||
|
|||
## Browsers support |
|||
|
|||
Modern browsers and Internet Explorer 10+. |
|||
|
|||
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | |
|||
| --------- | --------- | --------- | --------- | |
|||
| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions |
|||
|
|||
## License |
|||
|
|||
[MIT](https://github.com/PanJiaChen/vue-admin-template/blob/master/LICENSE) license. |
|||
|
|||
Copyright (c) 2017-present PanJiaChen |
|||
@ -0,0 +1,99 @@ |
|||
# vue-admin-template |
|||
|
|||
English | [简体中文](./README-zh.md) |
|||
|
|||
> A minimal vue admin template with Element UI & axios & iconfont & permission control & lint |
|||
|
|||
**Live demo:** http://panjiachen.github.io/vue-admin-template |
|||
|
|||
|
|||
**The current version is `v4.0+` build on `vue-cli`. If you want to use the old version , you can switch branch to [tag/3.11.0](https://github.com/PanJiaChen/vue-admin-template/tree/tag/3.11.0), it does not rely on `vue-cli`** |
|||
|
|||
<p align="center"> |
|||
<b>SPONSORED BY</b> |
|||
</p> |
|||
<p align="center"> |
|||
<a href="https://finclip.com?from=vue_element" title="FinClip" target="_blank"> |
|||
<img height="200px" src="https://gitee.com/panjiachen/gitee-cdn/raw/master/vue%E8%B5%9E%E5%8A%A9.png" title="FinClip"> |
|||
</a> |
|||
</p> |
|||
|
|||
## Build Setup |
|||
|
|||
```bash |
|||
# clone the project |
|||
git clone https://github.com/PanJiaChen/vue-admin-template.git |
|||
|
|||
# enter the project directory |
|||
cd vue-admin-template |
|||
|
|||
# install dependency |
|||
npm install |
|||
|
|||
# develop |
|||
npm run dev |
|||
``` |
|||
|
|||
This will automatically open http://localhost:9528 |
|||
|
|||
## Build |
|||
|
|||
```bash |
|||
# build for test environment |
|||
npm run build:stage |
|||
|
|||
# build for production environment |
|||
npm run build:prod |
|||
``` |
|||
|
|||
## Advanced |
|||
|
|||
```bash |
|||
# preview the release environment effect |
|||
npm run preview |
|||
|
|||
# preview the release environment effect + static resource analysis |
|||
npm run preview -- --report |
|||
|
|||
# code format check |
|||
npm run lint |
|||
|
|||
# code format check and auto fix |
|||
npm run lint -- --fix |
|||
``` |
|||
|
|||
Refer to [Documentation](https://panjiachen.github.io/vue-element-admin-site/guide/essentials/deploy.html) for more information |
|||
|
|||
## Demo |
|||
|
|||
 |
|||
|
|||
## Extra |
|||
|
|||
If you want router permission && generate menu by user roles , you can use this branch [permission-control](https://github.com/PanJiaChen/vue-admin-template/tree/permission-control) |
|||
|
|||
For `typescript` version, you can use [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) (Credits: [@Armour](https://github.com/Armour)) |
|||
|
|||
## Related Project |
|||
|
|||
- [vue-element-admin](https://github.com/PanJiaChen/vue-element-admin) |
|||
|
|||
- [electron-vue-admin](https://github.com/PanJiaChen/electron-vue-admin) |
|||
|
|||
- [vue-typescript-admin-template](https://github.com/Armour/vue-typescript-admin-template) |
|||
|
|||
- [awesome-project](https://github.com/PanJiaChen/vue-element-admin/issues/2312) |
|||
|
|||
## Browsers support |
|||
|
|||
Modern browsers and Internet Explorer 10+. |
|||
|
|||
| [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/edge/edge_48x48.png" alt="IE / Edge" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>IE / Edge | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/firefox/firefox_48x48.png" alt="Firefox" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Firefox | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/chrome/chrome_48x48.png" alt="Chrome" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Chrome | [<img src="https://raw.githubusercontent.com/alrra/browser-logos/master/src/safari/safari_48x48.png" alt="Safari" width="24px" height="24px" />](http://godban.github.io/browsers-support-badges/)</br>Safari | |
|||
| --------- | --------- | --------- | --------- | |
|||
| IE10, IE11, Edge| last 2 versions| last 2 versions| last 2 versions |
|||
|
|||
## License |
|||
|
|||
[MIT](https://github.com/PanJiaChen/vue-admin-template/blob/master/LICENSE) license. |
|||
|
|||
Copyright (c) 2017-present PanJiaChen |
|||
@ -0,0 +1,14 @@ |
|||
module.exports = { |
|||
presets: [ |
|||
// https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app
|
|||
'@vue/cli-plugin-babel/preset' |
|||
], |
|||
'env': { |
|||
'development': { |
|||
// babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
|
|||
// This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
|
|||
// https://panjiachen.github.io/vue-element-admin-site/guide/advanced/lazy-loading.html
|
|||
'plugins': ['dynamic-import-node'] |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,35 @@ |
|||
const { run } = require('runjs') |
|||
const chalk = require('chalk') |
|||
const config = require('../vue.config.js') |
|||
const rawArgv = process.argv.slice(2) |
|||
const args = rawArgv.join(' ') |
|||
|
|||
if (process.env.npm_config_preview || rawArgv.includes('--preview')) { |
|||
const report = rawArgv.includes('--report') |
|||
|
|||
run(`vue-cli-service build ${args}`) |
|||
|
|||
const port = 9526 |
|||
const publicPath = config.publicPath |
|||
|
|||
var connect = require('connect') |
|||
var serveStatic = require('serve-static') |
|||
const app = connect() |
|||
|
|||
app.use( |
|||
publicPath, |
|||
serveStatic('./dist', { |
|||
index: ['index.html', '/'] |
|||
}) |
|||
) |
|||
|
|||
app.listen(port, function () { |
|||
console.log(chalk.green(`> Preview at http://localhost:${port}${publicPath}`)) |
|||
if (report) { |
|||
console.log(chalk.green(`> Report at http://localhost:${port}${publicPath}report.html`)) |
|||
} |
|||
|
|||
}) |
|||
} else { |
|||
run(`vue-cli-service build ${args}`) |
|||
} |
|||
@ -0,0 +1,24 @@ |
|||
module.exports = { |
|||
moduleFileExtensions: ['js', 'jsx', 'json', 'vue'], |
|||
transform: { |
|||
'^.+\\.vue$': 'vue-jest', |
|||
'.+\\.(css|styl|less|sass|scss|svg|png|jpg|ttf|woff|woff2)$': |
|||
'jest-transform-stub', |
|||
'^.+\\.jsx?$': 'babel-jest' |
|||
}, |
|||
moduleNameMapper: { |
|||
'^@/(.*)$': '<rootDir>/src/$1' |
|||
}, |
|||
snapshotSerializers: ['jest-serializer-vue'], |
|||
testMatch: [ |
|||
'**/tests/unit/**/*.spec.(js|jsx|ts|tsx)|**/__tests__/*.(js|jsx|ts|tsx)' |
|||
], |
|||
collectCoverageFrom: ['src/utils/**/*.{js,vue}', '!src/utils/auth.js', '!src/utils/request.js', 'src/components/**/*.{js,vue}'], |
|||
coverageDirectory: '<rootDir>/tests/unit/coverage', |
|||
// 'collectCoverage': true,
|
|||
'coverageReporters': [ |
|||
'lcov', |
|||
'text-summary' |
|||
], |
|||
testURL: 'http://gin.vueadmin.net/' |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
{ |
|||
"compilerOptions": { |
|||
"baseUrl": "./", |
|||
"paths": { |
|||
"@/*": ["src/*"] |
|||
} |
|||
}, |
|||
"exclude": ["node_modules", "dist"] |
|||
} |
|||
@ -0,0 +1,57 @@ |
|||
const Mock = require('mockjs') |
|||
const { param2Obj } = require('./utils') |
|||
|
|||
const user = require('./user') |
|||
const table = require('./table') |
|||
|
|||
const mocks = [ |
|||
...user, |
|||
...table |
|||
] |
|||
|
|||
// for front mock
|
|||
// please use it cautiously, it will redefine XMLHttpRequest,
|
|||
// which will cause many of your third-party libraries to be invalidated(like progress event).
|
|||
function mockXHR() { |
|||
// mock patch
|
|||
// https://github.com/nuysoft/Mock/issues/300
|
|||
Mock.XHR.prototype.proxy_send = Mock.XHR.prototype.send |
|||
Mock.XHR.prototype.send = function() { |
|||
if (this.custom.xhr) { |
|||
this.custom.xhr.withCredentials = this.withCredentials || false |
|||
|
|||
if (this.responseType) { |
|||
this.custom.xhr.responseType = this.responseType |
|||
} |
|||
} |
|||
this.proxy_send(...arguments) |
|||
} |
|||
|
|||
function XHR2ExpressReqWrap(respond) { |
|||
return function(options) { |
|||
let result = null |
|||
if (respond instanceof Function) { |
|||
const { body, type, url } = options |
|||
// https://expressjs.com/en/4x/api.html#req
|
|||
result = respond({ |
|||
method: type, |
|||
body: JSON.parse(body), |
|||
query: param2Obj(url) |
|||
}) |
|||
} else { |
|||
result = respond |
|||
} |
|||
return Mock.mock(result) |
|||
} |
|||
} |
|||
|
|||
for (const i of mocks) { |
|||
Mock.mock(new RegExp(i.url), i.type || 'get', XHR2ExpressReqWrap(i.response)) |
|||
} |
|||
} |
|||
|
|||
module.exports = { |
|||
mocks, |
|||
mockXHR |
|||
} |
|||
|
|||
@ -0,0 +1,81 @@ |
|||
const chokidar = require('chokidar') |
|||
const bodyParser = require('body-parser') |
|||
const chalk = require('chalk') |
|||
const path = require('path') |
|||
const Mock = require('mockjs') |
|||
|
|||
const mockDir = path.join(process.cwd(), 'mock') |
|||
|
|||
function registerRoutes(app) { |
|||
let mockLastIndex |
|||
const { mocks } = require('./index.js') |
|||
const mocksForServer = mocks.map(route => { |
|||
return responseFake(route.url, route.type, route.response) |
|||
}) |
|||
for (const mock of mocksForServer) { |
|||
app[mock.type](mock.url, mock.response) |
|||
mockLastIndex = app._router.stack.length |
|||
} |
|||
const mockRoutesLength = Object.keys(mocksForServer).length |
|||
return { |
|||
mockRoutesLength: mockRoutesLength, |
|||
mockStartIndex: mockLastIndex - mockRoutesLength |
|||
} |
|||
} |
|||
|
|||
function unregisterRoutes() { |
|||
Object.keys(require.cache).forEach(i => { |
|||
if (i.includes(mockDir)) { |
|||
delete require.cache[require.resolve(i)] |
|||
} |
|||
}) |
|||
} |
|||
|
|||
// for mock server
|
|||
const responseFake = (url, type, respond) => { |
|||
return { |
|||
url: new RegExp(`${process.env.VUE_APP_BASE_API}${url}`), |
|||
type: type || 'get', |
|||
response(req, res) { |
|||
console.log('request invoke:' + req.path) |
|||
res.json(Mock.mock(respond instanceof Function ? respond(req, res) : respond)) |
|||
} |
|||
} |
|||
} |
|||
|
|||
module.exports = app => { |
|||
// parse app.body
|
|||
// https://expressjs.com/en/4x/api.html#req.body
|
|||
app.use(bodyParser.json()) |
|||
app.use(bodyParser.urlencoded({ |
|||
extended: true |
|||
})) |
|||
|
|||
const mockRoutes = registerRoutes(app) |
|||
var mockRoutesLength = mockRoutes.mockRoutesLength |
|||
var mockStartIndex = mockRoutes.mockStartIndex |
|||
|
|||
// watch files, hot reload mock server
|
|||
chokidar.watch(mockDir, { |
|||
ignored: /mock-server/, |
|||
ignoreInitial: true |
|||
}).on('all', (event, path) => { |
|||
if (event === 'change' || event === 'add') { |
|||
try { |
|||
// remove mock routes stack
|
|||
app._router.stack.splice(mockStartIndex, mockRoutesLength) |
|||
|
|||
// clear routes cache
|
|||
unregisterRoutes() |
|||
|
|||
const mockRoutes = registerRoutes(app) |
|||
mockRoutesLength = mockRoutes.mockRoutesLength |
|||
mockStartIndex = mockRoutes.mockStartIndex |
|||
|
|||
console.log(chalk.magentaBright(`\n > Mock Server hot reload success! changed ${path}`)) |
|||
} catch (error) { |
|||
console.log(chalk.redBright(error)) |
|||
} |
|||
} |
|||
}) |
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
const Mock = require('mockjs') |
|||
|
|||
const data = Mock.mock({ |
|||
'items|30': [{ |
|||
id: '@id', |
|||
title: '@sentence(10, 20)', |
|||
'status|1': ['published', 'draft', 'deleted'], |
|||
author: 'name', |
|||
display_time: '@datetime', |
|||
pageviews: '@integer(300, 5000)' |
|||
}] |
|||
}) |
|||
|
|||
module.exports = [ |
|||
{ |
|||
url: '/vue-admin-template/table/list', |
|||
type: 'get', |
|||
response: config => { |
|||
const items = data.items |
|||
return { |
|||
code: 20000, |
|||
data: { |
|||
total: items.length, |
|||
items: items |
|||
} |
|||
} |
|||
} |
|||
} |
|||
] |
|||
@ -0,0 +1,84 @@ |
|||
|
|||
const tokens = { |
|||
admin: { |
|||
token: 'admin-token' |
|||
}, |
|||
editor: { |
|||
token: 'editor-token' |
|||
} |
|||
} |
|||
|
|||
const users = { |
|||
'admin-token': { |
|||
roles: ['admin'], |
|||
introduction: 'I am a super administrator', |
|||
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', |
|||
name: 'Super Admin' |
|||
}, |
|||
'editor-token': { |
|||
roles: ['editor'], |
|||
introduction: 'I am an editor', |
|||
avatar: 'https://wpimg.wallstcn.com/f778738c-e4f8-4870-b634-56703b4acafe.gif', |
|||
name: 'Normal Editor' |
|||
} |
|||
} |
|||
|
|||
module.exports = [ |
|||
// user login
|
|||
{ |
|||
url: '/vue-admin-template/user/login', |
|||
type: 'post', |
|||
response: config => { |
|||
const { username } = config.body |
|||
const token = tokens[username] |
|||
|
|||
// mock error
|
|||
if (!token) { |
|||
return { |
|||
code: 60204, |
|||
message: 'Account and password are incorrect.' |
|||
} |
|||
} |
|||
|
|||
return { |
|||
code: 20000, |
|||
data: token |
|||
} |
|||
} |
|||
}, |
|||
|
|||
// get user info
|
|||
{ |
|||
url: '/vue-admin-template/user/info\.*', |
|||
type: 'get', |
|||
response: config => { |
|||
const { token } = config.query |
|||
const info = users[token] |
|||
|
|||
// mock error
|
|||
if (!info) { |
|||
return { |
|||
code: 50008, |
|||
message: 'Login failed, unable to get user details.' |
|||
} |
|||
} |
|||
|
|||
return { |
|||
code: 20000, |
|||
data: info |
|||
} |
|||
} |
|||
}, |
|||
|
|||
// user logout
|
|||
{ |
|||
url: '/vue-admin-template/user/logout', |
|||
type: 'post', |
|||
response: _ => { |
|||
return { |
|||
code: 20000, |
|||
data: 'success' |
|||
} |
|||
} |
|||
} |
|||
] |
|||
@ -0,0 +1,25 @@ |
|||
/** |
|||
* @param {string} url |
|||
* @returns {Object} |
|||
*/ |
|||
function param2Obj(url) { |
|||
const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ') |
|||
if (!search) { |
|||
return {} |
|||
} |
|||
const obj = {} |
|||
const searchArr = search.split('&') |
|||
searchArr.forEach(v => { |
|||
const index = v.indexOf('=') |
|||
if (index !== -1) { |
|||
const name = v.substring(0, index) |
|||
const val = v.substring(index + 1, v.length) |
|||
obj[name] = val |
|||
} |
|||
}) |
|||
return obj |
|||
} |
|||
|
|||
module.exports = { |
|||
param2Obj |
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
{ |
|||
"name": "vue-admin-template", |
|||
"version": "4.4.0", |
|||
"description": "A vue admin template with Element UI & axios & iconfont & permission control & lint", |
|||
"author": "Pan <panfree23@gmail.com>", |
|||
"scripts": { |
|||
"dev": "vue-cli-service serve", |
|||
"build:prod": "vue-cli-service build", |
|||
"build:stage": "vue-cli-service build --mode staging", |
|||
"preview": "node build/index.js --preview", |
|||
"svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml", |
|||
"lint": "eslint --ext .js,.vue src", |
|||
"test:unit": "jest --clearCache && vue-cli-service test:unit", |
|||
"test:ci": "npm run lint && npm run test:unit" |
|||
}, |
|||
"dependencies": { |
|||
"axios": "0.18.1", |
|||
"core-js": "^3.20.2", |
|||
"element-ui": "2.15.6", |
|||
"js-cookie": "2.2.0", |
|||
"normalize.css": "7.0.0", |
|||
"nprogress": "0.2.0", |
|||
"path-to-regexp": "2.4.0", |
|||
"vue": "2.6.10", |
|||
"vue-router": "3.0.6", |
|||
"vuex": "3.1.0" |
|||
}, |
|||
"devDependencies": { |
|||
"@vue/cli-plugin-babel": "4.4.4", |
|||
"@vue/cli-plugin-eslint": "4.4.4", |
|||
"@vue/cli-plugin-unit-jest": "4.4.4", |
|||
"@vue/cli-service": "4.4.4", |
|||
"@vue/test-utils": "1.0.0-beta.29", |
|||
"autoprefixer": "9.5.1", |
|||
"babel-eslint": "10.1.0", |
|||
"babel-jest": "23.6.0", |
|||
"babel-plugin-dynamic-import-node": "2.3.3", |
|||
"chalk": "2.4.2", |
|||
"connect": "3.6.6", |
|||
"eslint": "6.7.2", |
|||
"eslint-plugin-vue": "6.2.2", |
|||
"html-webpack-plugin": "3.2.0", |
|||
"mockjs": "1.0.1-beta3", |
|||
"runjs": "4.3.2", |
|||
"sass": "1.26.8", |
|||
"sass-loader": "8.0.2", |
|||
"script-ext-html-webpack-plugin": "2.1.3", |
|||
"serve-static": "1.13.2", |
|||
"svg-sprite-loader": "4.1.3", |
|||
"svgo": "1.2.2", |
|||
"vue-template-compiler": "2.6.10" |
|||
}, |
|||
"browserslist": [ |
|||
"> 1%", |
|||
"last 2 versions" |
|||
], |
|||
"engines": { |
|||
"node": ">=8.9", |
|||
"npm": ">= 3.0.0" |
|||
}, |
|||
"license": "MIT" |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
// https://github.com/michael-ciniawsky/postcss-load-config
|
|||
|
|||
module.exports = { |
|||
'plugins': { |
|||
// to edit target browsers: use "browserslist" field in package.json
|
|||
'autoprefixer': {} |
|||
} |
|||
} |
|||
|
After Width: | Height: | Size: 66 KiB |
|
After Width: | Height: | Size: 72 KiB |
@ -0,0 +1,19 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no"> |
|||
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> |
|||
<title><%= webpackConfig.name %></title> |
|||
<script src="//res.wx.qq.com/open/js/jweixin-1.2.0.js"></script> |
|||
<script src="https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"></script> |
|||
</head> |
|||
<body> |
|||
<noscript> |
|||
<strong>We're sorry but <%= webpackConfig.name %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong> |
|||
</noscript> |
|||
<div id="app"></div> |
|||
<!-- built files will be auto injected --> |
|||
</body> |
|||
</html> |
|||
@ -0,0 +1,11 @@ |
|||
<template> |
|||
<div id="app"> |
|||
<router-view /> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'App' |
|||
} |
|||
</script> |
|||
@ -0,0 +1,209 @@ |
|||
import request from '@/utils/request' |
|||
//个人需要填写的考核项目
|
|||
export function myassessmentlist(params) { |
|||
return request({ |
|||
url: '/dutys/myassessmentlist', |
|||
method: 'post', |
|||
params |
|||
}) |
|||
} |
|||
//根据具体考核项目获取被考核部门
|
|||
export const getDutydepartlist = (data) => { |
|||
return request({ |
|||
url: '/dutys/getDutydepartlist', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//根据具体考核项目获取被考核部门
|
|||
export const addassessmentscore = (data) => { |
|||
return request({ |
|||
url: '/dutys/addassessmentscore', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//个人考核评价记录
|
|||
export const myevaluatelist = (data) => { |
|||
return request({ |
|||
url: '/dutys/myevaluatelist', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//根据部门和时间获取考核详情
|
|||
export const getdeparttimeassess = (data) => { |
|||
return request({ |
|||
url: '/dutys/getdeparttimeassess', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//获取企业微信发起基础配置
|
|||
export const getconfig = (data) => { |
|||
return request({ |
|||
url: '/examine/getconfig', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//以部门维度考核内容列表
|
|||
export const departmentassess = (data) => { |
|||
return request({ |
|||
url: '/dutys/departmentassess', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//根据部门和时间写入全部考核项分值
|
|||
export const departmentassessdata = (data) => { |
|||
return request({ |
|||
url: '/dutys/departmentassessdata', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//查看审批详细内容
|
|||
export const lookdepartmentassessinfo = (data) => { |
|||
return request({ |
|||
url: '/noverify/lookdepartmentassessinfo', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//查看本部门提交的和个人提交的审批
|
|||
export const lookpersonalordepartment = (data) => { |
|||
return request({ |
|||
url: '/dutys/lookpersonalordepartment', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//定性考核列表
|
|||
export const qualevalulist = (data) => { |
|||
return request({ |
|||
url: '/eval/qualevalulist', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//添加加分或减分
|
|||
export const additionandsubtractionscore = (data) => { |
|||
return request({ |
|||
url: '/eval/plusorminuspoints', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//流程列表
|
|||
export const seeflowlog = (data) => { |
|||
return request({ |
|||
url: '/eval/seeflowlog', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//文档上传
|
|||
export const upordown = (data) => { |
|||
return request({ |
|||
url: '/upordown', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
// @Tags Api
|
|||
// @Summary 获取集团架构人员信息对照表
|
|||
// @Security ApiKeyAuth
|
|||
// @accept application/json
|
|||
// @Produce application/json
|
|||
// @Param data body dbModel.Api true "获取集团架构"
|
|||
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
|
|||
// @Router /group/grouplist [get]
|
|||
export const getgroupuser = (data) => { |
|||
return request({ |
|||
url: '/group/getgroupuser', |
|||
method: 'post', |
|||
data |
|||
}) |
|||
} |
|||
//划分责任人
|
|||
export const adddivisionresponsibility = (data) => { |
|||
return request({ |
|||
url: '/eval/rersonincharge', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//添加整改措施
|
|||
export const addcorrectivemeasures = (data) => { |
|||
return request({ |
|||
url: '/eval/rectificationmeasures', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//定量考核列表
|
|||
export const qualitativeevalration = (data) => { |
|||
return request({ |
|||
url: '/eval/qualitativeevalration', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//获取集团架构(集团+分厂)
|
|||
export const getgroupdepartmap = (data) => { |
|||
return request({ |
|||
url: '/group/getgroupdepartmap', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//获取分厂
|
|||
export const departmentlist = (data) => { |
|||
return request({ |
|||
url: '/group/departmentlist', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//定量考核打分
|
|||
export const addflowrationlog = (data) => { |
|||
return request({ |
|||
url: '/eval/addflowrationlog', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//查看定性考核审批列表
|
|||
export const lookdutkscoreflow = (data) => { |
|||
return request({ |
|||
url: '/eval/lookdutkscoreflow', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//查看定量考核
|
|||
export const lookrationkscoreflow = (data) => { |
|||
return request({ |
|||
url: '/eval/lookrationkscoreflow', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//获取班组
|
|||
export const getteamlist = (data) => { |
|||
return request({ |
|||
url: '/noverify/getteamlist', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//获取人员
|
|||
export const stafflist = (data) => { |
|||
return request({ |
|||
url: '/staff/stafflist', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
|
|||
@ -0,0 +1,24 @@ |
|||
import request from '@/utils/request' |
|||
// @Tags Api
|
|||
// @Summary 获取集团架构(集团+分厂)
|
|||
// @Security ApiKeyAuth
|
|||
// @accept application/json
|
|||
// @Produce application/json
|
|||
// @Param data body dbModel.Api true "获取集团架构"
|
|||
// @Success 200 {string} json "{"success":true,"data":{},"msg":"获取成功"}"
|
|||
// @Router /group/grouplist [get]
|
|||
export const getgroupdepartmap = (data) => { |
|||
return request({ |
|||
url: '/group/getgroupdepartmap', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//以部门维度考核内容列表
|
|||
export const departmentassess = (data) => { |
|||
return request({ |
|||
url: '/dutys/departmentassess', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
@ -0,0 +1,26 @@ |
|||
import request from '@/utils/request' |
|||
//个人需要填写的考核项目
|
|||
export const oauth2 = (data) => { |
|||
return request({ |
|||
url: '/base/oauth2', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
// @Summary 用户端登录
|
|||
// @Produce application/json
|
|||
// @Param data body {username:"string",password:"string"}
|
|||
// @Router /base/login [post]
|
|||
export const mylogin = (data) => { |
|||
return request({ |
|||
url: '/base/mylogin', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
export function logout() { |
|||
return request({ |
|||
url: '/vue-admin-template/user/logout', |
|||
method: 'post' |
|||
}) |
|||
} |
|||
@ -0,0 +1,75 @@ |
|||
import request from '@/utils/request' |
|||
//注销接口
|
|||
export function logout(params) { |
|||
return request({ |
|||
url: '/logout.do', |
|||
method: 'get', |
|||
params |
|||
}) |
|||
} |
|||
//登录接口
|
|||
export const login = (data) => { |
|||
return request({ |
|||
url: '/login.do', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//注册
|
|||
export const register = (data) => { |
|||
return request({ |
|||
url: '/login/register', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//绑定提现账户
|
|||
export const accountBinding = (data) => { |
|||
return request({ |
|||
url: '/user/accountBinding', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//申请提现
|
|||
export const withdraw = (data) => { |
|||
return request({ |
|||
url: '/user/withdraw', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//激活码激活
|
|||
export const cdkActivation = (data) => { |
|||
return request({ |
|||
url: '/user/cdkActivation', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//主页
|
|||
export const index = (data) => { |
|||
return request({ |
|||
url: '/user/index', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//开始任务按钮
|
|||
export const start = (data) => { |
|||
return request({ |
|||
url: '/user/start', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
//校验是否到期并且上传收益接口
|
|||
export const checkAndAdd = (data) => { |
|||
return request({ |
|||
url: '/user/checkAndAdd', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
|
|||
|
|||
@ -0,0 +1,9 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
export function getList(params) { |
|||
return request({ |
|||
url: '/vue-admin-template/table/list', |
|||
method: 'get', |
|||
params |
|||
}) |
|||
} |
|||
@ -0,0 +1,51 @@ |
|||
import request from '@/utils/request' |
|||
|
|||
export function login(data) { |
|||
return request({ |
|||
url: '/vue-admin-template/user/login', |
|||
method: 'post', |
|||
data |
|||
}) |
|||
} |
|||
|
|||
export function getInfo(token) { |
|||
return request({ |
|||
url: '/vue-admin-template/user/info', |
|||
method: 'get', |
|||
params: { token } |
|||
}) |
|||
} |
|||
// @Summary 获取验证码
|
|||
// @Produce application/json
|
|||
// @Param data body {username:"string",password:"string"}
|
|||
// @Router /base/captcha [post]
|
|||
// export const captcha = (data) => {
|
|||
// return service({
|
|||
// url: '/base/captcha',
|
|||
// method: 'post',
|
|||
// data: data
|
|||
// })
|
|||
// }
|
|||
export function captcha() { |
|||
return request({ |
|||
url: '/base/captcha', |
|||
method: 'post' |
|||
}) |
|||
} |
|||
// @Summary 用户端登录
|
|||
// @Produce application/json
|
|||
// @Param data body {username:"string",password:"string"}
|
|||
// @Router /base/login [post]
|
|||
export const mylogin = (data) => { |
|||
return request({ |
|||
url: '/base/mylogin', |
|||
method: 'post', |
|||
data: data |
|||
}) |
|||
} |
|||
export function logout() { |
|||
return request({ |
|||
url: '/vue-admin-template/user/logout', |
|||
method: 'post' |
|||
}) |
|||
} |
|||
|
After Width: | Height: | Size: 96 KiB |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 2.2 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 27 KiB |
|
After Width: | Height: | Size: 7.9 KiB |
|
After Width: | Height: | Size: 25 KiB |
|
After Width: | Height: | Size: 7.4 KiB |
@ -0,0 +1,78 @@ |
|||
<template> |
|||
<el-breadcrumb class="app-breadcrumb" separator="/"> |
|||
<transition-group name="breadcrumb"> |
|||
<el-breadcrumb-item v-for="(item,index) in levelList" :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() { |
|||
// only show routes with meta.title |
|||
let matched = this.$route.matched.filter(item => item.meta && item.meta.title) |
|||
const first = matched[0] |
|||
|
|||
if (!this.isDashboard(first)) { |
|||
matched = [{ path: '/dashboard', meta: { title: 'Dashboard' }}].concat(matched) |
|||
} |
|||
|
|||
this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false) |
|||
}, |
|||
isDashboard(route) { |
|||
const name = route && route.name |
|||
if (!name) { |
|||
return false |
|||
} |
|||
return name.trim().toLocaleLowerCase() === 'Dashboard'.toLocaleLowerCase() |
|||
}, |
|||
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 lang="scss" scoped> |
|||
.app-breadcrumb.el-breadcrumb { |
|||
display: inline-block; |
|||
font-size: 14px; |
|||
line-height: 50px; |
|||
margin-left: 8px; |
|||
|
|||
.no-redirect { |
|||
color: #97a8be; |
|||
cursor: text; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,44 @@ |
|||
<template> |
|||
<div style="padding: 0 15px;" @click="toggleClick"> |
|||
<svg |
|||
:class="{'is-active':isActive}" |
|||
class="hamburger" |
|||
viewBox="0 0 1024 1024" |
|||
xmlns="http://www.w3.org/2000/svg" |
|||
width="64" |
|||
height="64" |
|||
> |
|||
<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 |
|||
} |
|||
}, |
|||
methods: { |
|||
toggleClick() { |
|||
this.$emit('toggleClick') |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.hamburger { |
|||
display: inline-block; |
|||
vertical-align: middle; |
|||
width: 20px; |
|||
height: 20px; |
|||
} |
|||
|
|||
.hamburger.is-active { |
|||
transform: rotate(180deg); |
|||
} |
|||
</style> |
|||
@ -0,0 +1,62 @@ |
|||
<template> |
|||
<div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" /> |
|||
<svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners"> |
|||
<use :xlink:href="iconName" /> |
|||
</svg> |
|||
</template> |
|||
|
|||
<script> |
|||
// doc: https://panjiachen.github.io/vue-element-admin-site/feature/component/svg-icon.html#usage |
|||
import { isExternal } from '@/utils/validate' |
|||
|
|||
export default { |
|||
name: 'SvgIcon', |
|||
props: { |
|||
iconClass: { |
|||
type: String, |
|||
required: true |
|||
}, |
|||
className: { |
|||
type: String, |
|||
default: '' |
|||
} |
|||
}, |
|||
computed: { |
|||
isExternal() { |
|||
return isExternal(this.iconClass) |
|||
}, |
|||
iconName() { |
|||
return `#icon-${this.iconClass}` |
|||
}, |
|||
svgClass() { |
|||
if (this.className) { |
|||
return 'svg-icon ' + this.className |
|||
} else { |
|||
return 'svg-icon' |
|||
} |
|||
}, |
|||
styleExternalIcon() { |
|||
return { |
|||
mask: `url(${this.iconClass}) no-repeat 50% 50%`, |
|||
'-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%` |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.svg-icon { |
|||
width: 1em; |
|||
height: 1em; |
|||
vertical-align: -0.15em; |
|||
fill: currentColor; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.svg-external-icon { |
|||
background-color: currentColor; |
|||
mask-size: cover!important; |
|||
display: inline-block; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,104 @@ |
|||
|
|||
<template> |
|||
<div> |
|||
<el-upload |
|||
:action="`http://gin.admin.net/upordown`" |
|||
|
|||
:show-file-list="false" |
|||
:on-success="handleImageSuccess" |
|||
:before-upload="beforeImageUpload" |
|||
:multiple="false" |
|||
> |
|||
<el-button size="mini" type="primary">压缩上传</el-button> |
|||
</el-upload> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import ImageCompress from '@/utils/image' |
|||
export default { |
|||
name: 'UploadImage', |
|||
model: { |
|||
prop: 'imageUrl', |
|||
event: 'change' |
|||
}, |
|||
props: { |
|||
imageUrl: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
fileSize: { |
|||
type: Number, |
|||
default: 2048 // 2M 超出后执行压缩 |
|||
}, |
|||
maxWH: { |
|||
type: Number, |
|||
default: 1920 // 图片长宽上限 |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
path: path |
|||
} |
|||
}, |
|||
computed: { |
|||
...mapGetters('user', ['userInfo', 'token']), |
|||
showImageUrl() { |
|||
return (this.imageUrl && this.imageUrl.slice(0, 4) !== 'http') ? path + this.imageUrl : this.imageUrl |
|||
} |
|||
}, |
|||
methods: { |
|||
beforeImageUpload(file) { |
|||
const isJPG = file.type === 'image/jpeg' |
|||
const isPng = file.type === 'image/png' |
|||
if (!isJPG && !isPng) { |
|||
this.$message.error('上传头像图片只能是 jpg或png 格式!') |
|||
return false |
|||
} |
|||
|
|||
const isRightSize = file.size / 1024 < this.fileSize |
|||
if (!isRightSize) { |
|||
// 压缩 |
|||
const compress = new ImageCompress(file, this.fileSize, this.maxWH) |
|||
return compress.compress() |
|||
} |
|||
return isRightSize |
|||
}, |
|||
handleImageSuccess(res) { |
|||
// this.imageUrl = URL.createObjectURL(file.raw); |
|||
const { data } = res |
|||
if (data.file) { |
|||
this.$emit('change', data.file.url) |
|||
this.$emit('on-success') |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.image-uploader { |
|||
border: 1px dashed #d9d9d9; |
|||
width: 180px; |
|||
border-radius: 6px; |
|||
cursor: pointer; |
|||
position: relative; |
|||
overflow: hidden; |
|||
} |
|||
.image-uploader { |
|||
border-color: #409eff; |
|||
} |
|||
.image-uploader-icon { |
|||
font-size: 28px; |
|||
color: #8c939d; |
|||
width: 178px; |
|||
height: 178px; |
|||
line-height: 178px; |
|||
text-align: center; |
|||
} |
|||
.image { |
|||
width: 178px; |
|||
height: 178px; |
|||
display: block; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,9 @@ |
|||
import Vue from 'vue' |
|||
import SvgIcon from '@/components/SvgIcon'// svg component
|
|||
|
|||
// register globally
|
|||
Vue.component('svg-icon', SvgIcon) |
|||
|
|||
const req = require.context('./svg', false, /\.svg$/) |
|||
const requireAll = requireContext => requireContext.keys().map(requireContext) |
|||
requireAll(req) |
|||
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 497 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 944 B |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 285 B |
|
After Width: | Height: | Size: 821 B |
|
After Width: | Height: | Size: 623 B |
|
After Width: | Height: | Size: 597 B |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 440 B |
@ -0,0 +1,22 @@ |
|||
# replace default config |
|||
|
|||
# multipass: true |
|||
# full: true |
|||
|
|||
plugins: |
|||
|
|||
# - name |
|||
# |
|||
# or: |
|||
# - name: false |
|||
# - name: true |
|||
# |
|||
# or: |
|||
# - name: |
|||
# param1: 1 |
|||
# param2: 2 |
|||
|
|||
- removeAttrs: |
|||
attrs: |
|||
- 'fill' |
|||
- 'fill-rule' |
|||
@ -0,0 +1,41 @@ |
|||
<template> |
|||
<section class="app-main"> |
|||
<transition name="fade-transform" mode="out-in"> |
|||
<router-view :key="key" /> |
|||
</transition> |
|||
</section> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'AppMain', |
|||
computed: { |
|||
key() { |
|||
|
|||
return this.$route.path |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.app-main { |
|||
/*50 = navbar */ |
|||
min-height: calc(100vh - 50px); |
|||
width: 100%; |
|||
position: relative; |
|||
overflow: hidden; |
|||
} |
|||
.fixed-header+.app-main { |
|||
padding-top: 50px; |
|||
} |
|||
</style> |
|||
|
|||
<style lang="scss"> |
|||
// fix css style bug in open el-dialog |
|||
.el-popup-parent--hidden { |
|||
.fixed-header { |
|||
padding-right: 15px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,158 @@ |
|||
<template> |
|||
<div class="navbar"> |
|||
<hamburger :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" /> |
|||
|
|||
<breadcrumb class="breadcrumb-container" /> |
|||
|
|||
<div class="right-menu"> |
|||
<el-dropdown class="avatar-container" trigger="click"> |
|||
<div class="avatar-wrapper"> |
|||
<!-- <img :src="avatar+'?imageView2/1/w/80/h/80'" class="user-avatar"> --> |
|||
<div> |
|||
{{userInfo.grouptitle}}{{userInfo.branchFactory}}{{userInfo.name}} |
|||
</div> |
|||
<i class="el-icon-caret-bottom" /> |
|||
</div> |
|||
<el-dropdown-menu slot="dropdown" class="user-dropdown"> |
|||
<router-link to="/"> |
|||
<el-dropdown-item> |
|||
个人信息 |
|||
</el-dropdown-item> |
|||
</router-link> |
|||
<!-- <a target="_blank" href="https://github.com/PanJiaChen/vue-admin-template/"> |
|||
<el-dropdown-item>Github</el-dropdown-item> |
|||
</a> |
|||
<a target="_blank" href="https://panjiachen.github.io/vue-element-admin-site/#/"> |
|||
<el-dropdown-item>Docs</el-dropdown-item> |
|||
</a> --> |
|||
<el-dropdown-item divided @click.native="logout"> |
|||
<span style="display:block;">退 出</span> |
|||
</el-dropdown-item> |
|||
</el-dropdown-menu> |
|||
</el-dropdown> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapGetters } from 'vuex' |
|||
import Breadcrumb from '@/components/Breadcrumb' |
|||
import Hamburger from '@/components/Hamburger' |
|||
|
|||
export default { |
|||
data () { |
|||
return { |
|||
userInfo:{} |
|||
} |
|||
}, |
|||
components: { |
|||
Breadcrumb, |
|||
Hamburger |
|||
}, |
|||
computed: { |
|||
...mapGetters([ |
|||
'sidebar', |
|||
'avatar' |
|||
]) |
|||
}, |
|||
created () { |
|||
if (JSON.parse(sessionStorage.getItem('userinfo'))==null) { |
|||
this.$router.push('/login') |
|||
} |
|||
if (this.$store.state.user.token=='') { |
|||
this.$router.push('/login') |
|||
} |
|||
if (this.$store.state.user.token==undefined) { |
|||
this.$router.push('/login') |
|||
} |
|||
this.userInfo=JSON.parse(sessionStorage.getItem('userinfo')); |
|||
}, |
|||
methods: { |
|||
toggleSideBar() { |
|||
this.$store.dispatch('app/toggleSideBar') |
|||
}, |
|||
logout() { |
|||
this.$store.commit('user/loginOut') |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.navbar { |
|||
height: 50px; |
|||
overflow: hidden; |
|||
position: relative; |
|||
background: #fff; |
|||
box-shadow: 0 1px 4px rgba(0,21,41,.08); |
|||
|
|||
.hamburger-container { |
|||
line-height: 46px; |
|||
height: 100%; |
|||
float: left; |
|||
cursor: pointer; |
|||
transition: background .3s; |
|||
-webkit-tap-highlight-color:transparent; |
|||
|
|||
&:hover { |
|||
background: rgba(0, 0, 0, .025) |
|||
} |
|||
} |
|||
|
|||
.breadcrumb-container { |
|||
float: left; |
|||
} |
|||
|
|||
.right-menu { |
|||
float: right; |
|||
height: 100%; |
|||
line-height: 50px; |
|||
|
|||
&:focus { |
|||
outline: none; |
|||
} |
|||
|
|||
.right-menu-item { |
|||
display: inline-block; |
|||
padding: 0 8px; |
|||
height: 100%; |
|||
font-size: 18px; |
|||
color: #5a5e66; |
|||
vertical-align: text-bottom; |
|||
|
|||
&.hover-effect { |
|||
cursor: pointer; |
|||
transition: background .3s; |
|||
|
|||
&:hover { |
|||
background: rgba(0, 0, 0, .025) |
|||
} |
|||
} |
|||
} |
|||
|
|||
.avatar-container { |
|||
margin-right: 30px; |
|||
|
|||
.avatar-wrapper { |
|||
margin-top: 5px; |
|||
position: relative; |
|||
|
|||
.user-avatar { |
|||
cursor: pointer; |
|||
width: 40px; |
|||
height: 40px; |
|||
border-radius: 10px; |
|||
} |
|||
|
|||
.el-icon-caret-bottom { |
|||
cursor: pointer; |
|||
position: absolute; |
|||
right: -20px; |
|||
top: 25px; |
|||
font-size: 12px; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,26 @@ |
|||
export default { |
|||
computed: { |
|||
device() { |
|||
return this.$store.state.app.device |
|||
} |
|||
}, |
|||
mounted() { |
|||
// In order to fix the click on menu on the ios device will trigger the mouseleave bug
|
|||
// https://github.com/PanJiaChen/vue-element-admin/issues/1135
|
|||
this.fixBugIniOS() |
|||
}, |
|||
methods: { |
|||
fixBugIniOS() { |
|||
const $subMenu = this.$refs.subMenu |
|||
if ($subMenu) { |
|||
const handleMouseleave = $subMenu.handleMouseleave |
|||
$subMenu.handleMouseleave = (e) => { |
|||
if (this.device === 'mobile') { |
|||
return |
|||
} |
|||
handleMouseleave(e) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
<script> |
|||
export default { |
|||
name: 'MenuItem', |
|||
functional: true, |
|||
props: { |
|||
icon: { |
|||
type: String, |
|||
default: '' |
|||
}, |
|||
title: { |
|||
type: String, |
|||
default: '' |
|||
} |
|||
}, |
|||
render(h, context) { |
|||
const { icon, title } = context.props |
|||
const vnodes = [] |
|||
|
|||
if (icon) { |
|||
if (icon.includes('el-icon')) { |
|||
vnodes.push(<i class={[icon, 'sub-el-icon']} />) |
|||
} else { |
|||
vnodes.push(<svg-icon icon-class={icon}/>) |
|||
} |
|||
} |
|||
|
|||
if (title) { |
|||
vnodes.push(<span slot='title'>{(title)}</span>) |
|||
} |
|||
return vnodes |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style scoped> |
|||
.sub-el-icon { |
|||
color: currentColor; |
|||
width: 1em; |
|||
height: 1em; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,43 @@ |
|||
<template> |
|||
<component :is="type" v-bind="linkProps(to)"> |
|||
<slot /> |
|||
</component> |
|||
</template> |
|||
|
|||
<script> |
|||
import { isExternal } from '@/utils/validate' |
|||
|
|||
export default { |
|||
props: { |
|||
to: { |
|||
type: String, |
|||
required: true |
|||
} |
|||
}, |
|||
computed: { |
|||
isExternal() { |
|||
return isExternal(this.to) |
|||
}, |
|||
type() { |
|||
if (this.isExternal) { |
|||
return 'a' |
|||
} |
|||
return 'router-link' |
|||
} |
|||
}, |
|||
methods: { |
|||
linkProps(to) { |
|||
if (this.isExternal) { |
|||
return { |
|||
href: to, |
|||
target: '_blank', |
|||
rel: 'noopener' |
|||
} |
|||
} |
|||
return { |
|||
to: to |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
@ -0,0 +1,82 @@ |
|||
<template> |
|||
<div class="sidebar-logo-container" :class="{'collapse':collapse}"> |
|||
<transition name="sidebarLogoFade"> |
|||
<router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/"> |
|||
<img v-if="logo" :src="logo" class="sidebar-logo"> |
|||
<h1 v-else class="sidebar-title">{{ title }} </h1> |
|||
</router-link> |
|||
<router-link v-else key="expand" class="sidebar-logo-link" to="/"> |
|||
<img v-if="logo" :src="logo" class="sidebar-logo"> |
|||
<h1 class="sidebar-title">{{ title }} </h1> |
|||
</router-link> |
|||
</transition> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
name: 'SidebarLogo', |
|||
props: { |
|||
collapse: { |
|||
type: Boolean, |
|||
required: true |
|||
} |
|||
}, |
|||
data() { |
|||
return { |
|||
title: 'Vue Admin Template', |
|||
logo: 'https://wpimg.wallstcn.com/69a1c46c-eb1c-4b46-8bd4-e9e686ef5251.png' |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.sidebarLogoFade-enter-active { |
|||
transition: opacity 1.5s; |
|||
} |
|||
|
|||
.sidebarLogoFade-enter, |
|||
.sidebarLogoFade-leave-to { |
|||
opacity: 0; |
|||
} |
|||
|
|||
.sidebar-logo-container { |
|||
position: relative; |
|||
width: 100%; |
|||
height: 50px; |
|||
line-height: 50px; |
|||
background: #2b2f3a; |
|||
text-align: center; |
|||
overflow: hidden; |
|||
|
|||
& .sidebar-logo-link { |
|||
height: 100%; |
|||
width: 100%; |
|||
|
|||
& .sidebar-logo { |
|||
width: 32px; |
|||
height: 32px; |
|||
vertical-align: middle; |
|||
margin-right: 12px; |
|||
} |
|||
|
|||
& .sidebar-title { |
|||
display: inline-block; |
|||
margin: 0; |
|||
color: #fff; |
|||
font-weight: 600; |
|||
line-height: 50px; |
|||
font-size: 14px; |
|||
font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif; |
|||
vertical-align: middle; |
|||
} |
|||
} |
|||
|
|||
&.collapse { |
|||
.sidebar-logo { |
|||
margin-right: 0px; |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,95 @@ |
|||
<template> |
|||
<div v-if="!item.hidden"> |
|||
<template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow"> |
|||
<app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)"> |
|||
<el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}"> |
|||
<item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" /> |
|||
</el-menu-item> |
|||
</app-link> |
|||
</template> |
|||
|
|||
<el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body> |
|||
<template slot="title"> |
|||
<item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" /> |
|||
</template> |
|||
<sidebar-item |
|||
v-for="child in item.children" |
|||
:key="child.path" |
|||
:is-nest="true" |
|||
:item="child" |
|||
:base-path="resolvePath(child.path)" |
|||
class="nest-menu" |
|||
/> |
|||
</el-submenu> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import path from 'path' |
|||
import { isExternal } from '@/utils/validate' |
|||
import Item from './Item' |
|||
import AppLink from './Link' |
|||
import FixiOSBug from './FixiOSBug' |
|||
|
|||
export default { |
|||
name: 'SidebarItem', |
|||
components: { Item, AppLink }, |
|||
mixins: [FixiOSBug], |
|||
props: { |
|||
// route object |
|||
item: { |
|||
type: Object, |
|||
required: true |
|||
}, |
|||
isNest: { |
|||
type: Boolean, |
|||
default: false |
|||
}, |
|||
basePath: { |
|||
type: String, |
|||
default: '' |
|||
} |
|||
}, |
|||
data() { |
|||
// To fix https://github.com/PanJiaChen/vue-admin-template/issues/237 |
|||
// TODO: refactor with render function |
|||
this.onlyOneChild = null |
|||
return {} |
|||
}, |
|||
methods: { |
|||
hasOneShowingChild(children = [], parent) { |
|||
const showingChildren = children.filter(item => { |
|||
if (item.hidden) { |
|||
return false |
|||
} else { |
|||
// Temp set(will be used if only has one showing child) |
|||
this.onlyOneChild = item |
|||
return true |
|||
} |
|||
}) |
|||
|
|||
// When there is only one child router, the child router is displayed by default |
|||
if (showingChildren.length === 1) { |
|||
return true |
|||
} |
|||
|
|||
// Show parent if there are no child router to display |
|||
if (showingChildren.length === 0) { |
|||
this.onlyOneChild = { ... parent, path: '', noShowingChildren: true } |
|||
return true |
|||
} |
|||
|
|||
return false |
|||
}, |
|||
resolvePath(routePath) { |
|||
if (isExternal(routePath)) { |
|||
return routePath |
|||
} |
|||
if (isExternal(this.basePath)) { |
|||
return this.basePath |
|||
} |
|||
return path.resolve(this.basePath, routePath) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
@ -0,0 +1,56 @@ |
|||
<template> |
|||
<div :class="{'has-logo':showLogo}"> |
|||
<logo v-if="showLogo" :collapse="isCollapse" /> |
|||
<el-scrollbar wrap-class="scrollbar-wrapper"> |
|||
<el-menu |
|||
:default-active="activeMenu" |
|||
:collapse="isCollapse" |
|||
:background-color="variables.menuBg" |
|||
:text-color="variables.menuText" |
|||
:unique-opened="false" |
|||
:active-text-color="variables.menuActiveText" |
|||
:collapse-transition="false" |
|||
mode="vertical" |
|||
> |
|||
<sidebar-item v-for="route in routes" :key="route.path" :item="route" :base-path="route.path" /> |
|||
</el-menu> |
|||
</el-scrollbar> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapGetters } from 'vuex' |
|||
import Logo from './Logo' |
|||
import SidebarItem from './SidebarItem' |
|||
import variables from '@/styles/variables.scss' |
|||
|
|||
export default { |
|||
components: { SidebarItem, Logo }, |
|||
computed: { |
|||
...mapGetters([ |
|||
'sidebar' |
|||
]), |
|||
routes() { |
|||
return this.$router.options.routes |
|||
}, |
|||
activeMenu() { |
|||
const route = this.$route |
|||
const { meta, path } = route |
|||
// if set path, the sidebar will highlight the path you set |
|||
if (meta.activeMenu) { |
|||
return meta.activeMenu |
|||
} |
|||
return path |
|||
}, |
|||
showLogo() { |
|||
return this.$store.state.settings.sidebarLogo |
|||
}, |
|||
variables() { |
|||
return variables |
|||
}, |
|||
isCollapse() { |
|||
return !this.sidebar.opened |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
@ -0,0 +1,3 @@ |
|||
export { default as Navbar } from './Navbar' |
|||
export { default as Sidebar } from './Sidebar' |
|||
export { default as AppMain } from './AppMain' |
|||
@ -0,0 +1,93 @@ |
|||
<template> |
|||
<div :class="classObj" class="app-wrapper"> |
|||
<div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" /> |
|||
<sidebar class="sidebar-container" /> |
|||
<div class="main-container"> |
|||
<div :class="{'fixed-header':fixedHeader}"> |
|||
<navbar /> |
|||
</div> |
|||
<app-main /> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { Navbar, Sidebar, AppMain } from './components' |
|||
import ResizeMixin from './mixin/ResizeHandler' |
|||
|
|||
export default { |
|||
name: 'Layout', |
|||
components: { |
|||
Navbar, |
|||
Sidebar, |
|||
AppMain |
|||
}, |
|||
mixins: [ResizeMixin], |
|||
computed: { |
|||
sidebar() { |
|||
return this.$store.state.app.sidebar |
|||
}, |
|||
device() { |
|||
return this.$store.state.app.device |
|||
}, |
|||
fixedHeader() { |
|||
return this.$store.state.settings.fixedHeader |
|||
}, |
|||
classObj() { |
|||
return { |
|||
hideSidebar: !this.sidebar.opened, |
|||
openSidebar: this.sidebar.opened, |
|||
withoutAnimation: this.sidebar.withoutAnimation, |
|||
mobile: this.device === 'mobile' |
|||
} |
|||
} |
|||
}, |
|||
methods: { |
|||
handleClickOutside() { |
|||
this.$store.dispatch('app/closeSideBar', { withoutAnimation: false }) |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
@import "~@/styles/mixin.scss"; |
|||
@import "~@/styles/variables.scss"; |
|||
|
|||
.app-wrapper { |
|||
@include clearfix; |
|||
position: relative; |
|||
height: 100%; |
|||
width: 100%; |
|||
&.mobile.openSidebar{ |
|||
position: fixed; |
|||
top: 0; |
|||
} |
|||
} |
|||
.drawer-bg { |
|||
background: #000; |
|||
opacity: 0.3; |
|||
width: 100%; |
|||
top: 0; |
|||
height: 100%; |
|||
position: absolute; |
|||
z-index: 999; |
|||
} |
|||
|
|||
.fixed-header { |
|||
position: fixed; |
|||
top: 0; |
|||
right: 0; |
|||
z-index: 9; |
|||
width: calc(100% - #{$sideBarWidth}); |
|||
transition: width 0.28s; |
|||
} |
|||
|
|||
.hideSidebar .fixed-header { |
|||
width: calc(100% - 54px) |
|||
} |
|||
|
|||
.mobile .fixed-header { |
|||
width: 100%; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,45 @@ |
|||
import store from '@/store' |
|||
|
|||
const { body } = document |
|||
const WIDTH = 992 // refer to Bootstrap's responsive design
|
|||
|
|||
export default { |
|||
watch: { |
|||
$route(route) { |
|||
if (this.device === 'mobile' && this.sidebar.opened) { |
|||
store.dispatch('app/closeSideBar', { withoutAnimation: false }) |
|||
} |
|||
} |
|||
}, |
|||
beforeMount() { |
|||
window.addEventListener('resize', this.$_resizeHandler) |
|||
}, |
|||
beforeDestroy() { |
|||
window.removeEventListener('resize', this.$_resizeHandler) |
|||
}, |
|||
mounted() { |
|||
const isMobile = this.$_isMobile() |
|||
if (isMobile) { |
|||
store.dispatch('app/toggleDevice', 'mobile') |
|||
store.dispatch('app/closeSideBar', { withoutAnimation: true }) |
|||
} |
|||
}, |
|||
methods: { |
|||
// use $_ for mixins properties
|
|||
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
|
|||
$_isMobile() { |
|||
const rect = body.getBoundingClientRect() |
|||
return rect.width - 1 < WIDTH |
|||
}, |
|||
$_resizeHandler() { |
|||
if (!document.hidden) { |
|||
const isMobile = this.$_isMobile() |
|||
store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop') |
|||
|
|||
if (isMobile) { |
|||
store.dispatch('app/closeSideBar', { withoutAnimation: true }) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,45 @@ |
|||
import store from '@/store' |
|||
|
|||
const { body } = document |
|||
const WIDTH = 992 // refer to Bootstrap's responsive design
|
|||
|
|||
export default { |
|||
watch: { |
|||
$route(route) { |
|||
if (this.device === 'mobile' && this.sidebar.opened) { |
|||
store.dispatch('app/closeSideBar', { withoutAnimation: false }) |
|||
} |
|||
} |
|||
}, |
|||
beforeMount() { |
|||
window.addEventListener('resize', this.$_resizeHandler) |
|||
}, |
|||
beforeDestroy() { |
|||
window.removeEventListener('resize', this.$_resizeHandler) |
|||
}, |
|||
mounted() { |
|||
const isMobile = this.$_isMobile() |
|||
if (isMobile) { |
|||
store.dispatch('app/toggleDevice', 'mobile') |
|||
store.dispatch('app/closeSideBar', { withoutAnimation: true }) |
|||
} |
|||
}, |
|||
methods: { |
|||
// use $_ for mixins properties
|
|||
// https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
|
|||
$_isMobile() { |
|||
const rect = body.getBoundingClientRect() |
|||
return rect.width - 1 < WIDTH |
|||
}, |
|||
$_resizeHandler() { |
|||
if (!document.hidden) { |
|||
const isMobile = this.$_isMobile() |
|||
store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop') |
|||
|
|||
if (isMobile) { |
|||
store.dispatch('app/closeSideBar', { withoutAnimation: true }) |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,43 @@ |
|||
import Vue from 'vue' |
|||
import axios from 'axios' |
|||
import 'normalize.css/normalize.css' // A modern alternative to CSS resets
|
|||
|
|||
import ElementUI from 'element-ui' |
|||
import 'element-ui/lib/theme-chalk/index.css' |
|||
// import locale from 'element-ui/lib/locale/lang/en' // lang i18n
|
|||
|
|||
import '@/styles/index.scss' // global css
|
|||
|
|||
import App from './App' |
|||
import store from './store' |
|||
import router from './router' |
|||
|
|||
import '@/icons' // icon
|
|||
// import '@/permission' // permission control
|
|||
|
|||
/** |
|||
* If you don't want to use mock-server |
|||
* you want to use MockJs for mock api |
|||
* you can execute: mockXHR() |
|||
* |
|||
* Currently MockJs will be used in the production environment, |
|||
* please remove it before going online ! ! ! |
|||
*/ |
|||
if (process.env.NODE_ENV === 'production') { |
|||
const { mockXHR } = require('../mock') |
|||
mockXHR() |
|||
} |
|||
|
|||
// set ElementUI lang to EN
|
|||
// Vue.use(ElementUI, { locale })
|
|||
// 如果想要中文版 element-ui,按如下方式声明
|
|||
Vue.use(ElementUI) |
|||
Vue.prototype.$axios = axios |
|||
Vue.config.productionTip = false |
|||
|
|||
new Vue({ |
|||
el: '#app', |
|||
router, |
|||
store, |
|||
render: h => h(App) |
|||
}) |
|||
@ -0,0 +1,75 @@ |
|||
|
|||
import { formatTimeToStr } from '@/utils/date' |
|||
|
|||
export default { |
|||
data() { |
|||
return { |
|||
page: 1, |
|||
total: 10, |
|||
pageSize: 10, |
|||
tableData: [], |
|||
tabledata:[], |
|||
searchInfo: {} |
|||
} |
|||
}, |
|||
methods: { |
|||
formatBoolean: function(bool) { |
|||
if (bool !== null) { |
|||
return bool ? '是' : '否' |
|||
} else { |
|||
return '' |
|||
} |
|||
}, |
|||
formatDate: function(time) { |
|||
if (time !== null && time !== '') { |
|||
var date = new Date(time) |
|||
return formatTimeToStr(date, 'yyyy-MM-dd hh:mm:ss') |
|||
} else { |
|||
return '' |
|||
} |
|||
}, |
|||
filterDict(value, type) { |
|||
const rowLabel = this[type + 'Options'] && this[type + 'Options'].filter(item => item.value === value) |
|||
return rowLabel && rowLabel[0] && rowLabel[0].label |
|||
}, |
|||
async getDict(type) { |
|||
const dicts = await getDict(type) |
|||
this[type + 'Options'] = dicts |
|||
return dicts |
|||
}, |
|||
handleSizeChange(val) { |
|||
this.pageSize = val |
|||
this.getTableData() |
|||
}, |
|||
handleCurrentChange(val) { |
|||
this.page = val |
|||
this.getTableData() |
|||
}, |
|||
// @params beforeFunc function 请求发起前执行的函数 默认为空函数
|
|||
// @params afterFunc function 请求完成后执行的函数 默认为空函数
|
|||
async getTableData(beforeFunc = () => {}, afterFunc = () => {}) { |
|||
beforeFunc() |
|||
const table = await this.listApi({ page: this.page, pageSize: this.pageSize, ...this.searchInfo }) |
|||
// console.log(table.code)
|
|||
// console.log("datalist")
|
|||
// console.log(table.data)
|
|||
if (table.code === 0) { |
|||
this.tableData = table.data.list |
|||
this.total = table.data.total |
|||
this.count = table.data.count |
|||
this.page = table.data.page |
|||
this.pageSize = table.data.pageSize |
|||
this.pagesize = table.data.pagesize |
|||
this.tabledata = table.data.data |
|||
// if (table.data.data!='') {
|
|||
// this.tableData = table.data.data
|
|||
// }
|
|||
} |
|||
if (table.code === 200) { |
|||
this.tableData = table.data |
|||
} |
|||
|
|||
afterFunc() |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,79 @@ |
|||
import router from './router' |
|||
import store from './store' |
|||
import { Message } from 'element-ui' |
|||
import NProgress from 'nprogress' // progress bar
|
|||
import 'nprogress/nprogress.css' // progress bar style
|
|||
import { getToken } from '@/utils/auth' // get token from cookie
|
|||
import getPageTitle from '@/utils/get-page-title' |
|||
|
|||
NProgress.configure({ showSpinner: false }) // NProgress Configuration
|
|||
|
|||
const whiteList = ['/login'] // no redirect whitelist
|
|||
|
|||
router.beforeEach(async(to, from, next) => { |
|||
// start progress bar
|
|||
NProgress.start() |
|||
|
|||
// set page title
|
|||
document.title = getPageTitle(to.meta.title) |
|||
|
|||
// determine whether the user has logged in
|
|||
const hasToken = getToken() |
|||
if (hasToken!='') { |
|||
next({path:'/index'}) |
|||
} else { |
|||
next({path:'/login'}) |
|||
} |
|||
// if (hasToken) {
|
|||
// console.log("hasToken")
|
|||
// console.log(hasToken)
|
|||
// // if (to.path === '/login') {
|
|||
// // console.log("111")
|
|||
// // // if is logged in, redirect to the home page
|
|||
// // next({ path: '/' })
|
|||
// // NProgress.done()
|
|||
// // } else {
|
|||
// // console.log("222")
|
|||
// // const hasGetUserInfo = store.getters.name
|
|||
// // if (hasGetUserInfo) {
|
|||
// // console.log("333")
|
|||
// // next()
|
|||
|
|||
// // } else {
|
|||
// // try {
|
|||
// // console.log("444")
|
|||
// // // get user info
|
|||
// // await store.dispatch('user/getInfo')
|
|||
|
|||
// // next()
|
|||
// // } catch (error) {
|
|||
// // console.log("555")
|
|||
// // // remove token and go to login page to re-login
|
|||
// // await store.dispatch('user/resetToken')
|
|||
// // Message.error(error || 'Has Error')
|
|||
// // next(`/login?redirect=${to.path}`)
|
|||
// // NProgress.done()
|
|||
// // }
|
|||
// // }
|
|||
// // }
|
|||
// } else {
|
|||
// console.log("666")
|
|||
// /* has no token*/
|
|||
|
|||
// if (whiteList.indexOf(to.path) !== -1) {
|
|||
// console.log("777")
|
|||
// // in the free login whitelist, go directly
|
|||
// next()
|
|||
// } else {
|
|||
// console.log("888")
|
|||
// // other pages that do not have permission to access are redirected to the login page.
|
|||
// next(`/login?redirect=${to.path}`)
|
|||
// NProgress.done()
|
|||
// }
|
|||
// }
|
|||
}) |
|||
|
|||
router.afterEach(() => { |
|||
// finish progress bar
|
|||
NProgress.done() |
|||
}) |
|||
@ -0,0 +1,295 @@ |
|||
import Vue from 'vue' |
|||
import Router from 'vue-router' |
|||
|
|||
Vue.use(Router) |
|||
|
|||
/* Layout */ |
|||
import Layout from '@/layout' |
|||
|
|||
/** |
|||
* Note: sub-menu only appear when route children.length >= 1 |
|||
* Detail see: https://panjiachen.github.io/vue-element-admin-site/guide/essentials/router-and-nav.html
|
|||
* |
|||
* hidden: true if set true, item will not show in the sidebar(default is false) |
|||
* alwaysShow: true if set true, will always show the root menu |
|||
* if not set alwaysShow, when item has more than one children route, |
|||
* it will becomes nested mode, otherwise not show the root menu |
|||
* redirect: noRedirect if set noRedirect will no redirect in the breadcrumb |
|||
* name:'router-name' the name is used by <keep-alive> (must set!!!) |
|||
* meta : { |
|||
roles: ['admin','editor'] control the page roles (you can set multiple roles) |
|||
title: 'title' the name show in sidebar and breadcrumb (recommend set) |
|||
icon: 'svg-name'/'el-icon-x' the icon show in the sidebar |
|||
breadcrumb: false if set false, the item will hidden in breadcrumb(default is true) |
|||
activeMenu: '/example/list' if set path, the sidebar will highlight the path you set |
|||
} |
|||
*/ |
|||
|
|||
/** |
|||
* constantRoutes |
|||
* a base page that does not have permission requirements |
|||
* all roles can be accessed |
|||
*/ |
|||
export const constantRoutes = [ |
|||
{ |
|||
path: '/login', |
|||
component: () => import('@/views/login/index'), |
|||
hidden: true |
|||
}, |
|||
{ |
|||
path: '/ceshi', |
|||
component: () => import('@/views/ceshi/index'), |
|||
hidden: true |
|||
}, |
|||
{ |
|||
path: '/zerenLogin', |
|||
component: () => import('@/views/login/zerenLogin'), |
|||
hidden: true |
|||
}, |
|||
{ |
|||
path: '/zhenggaiLogin', |
|||
component: () => import('@/views/login/zhenggaiLogin'), |
|||
hidden: true |
|||
}, |
|||
{ |
|||
path: '/quantitativeListLogin', |
|||
component: () => import('@/views/login/quantitativeListLogin'), |
|||
hidden: true |
|||
}, |
|||
{ |
|||
path: '/dingxingLogin', |
|||
component: () => import('@/views/login/dingxingLogin'), |
|||
hidden: true |
|||
}, |
|||
{ |
|||
path: '/responsible', |
|||
component: () => import('@/views/responsible/index'), |
|||
hidden: true |
|||
}, |
|||
{ |
|||
path: '/quantitativeList', |
|||
component: () => import('@/views/quantitativeList/index'), |
|||
hidden: true |
|||
}, |
|||
{ |
|||
path: '/approvalList', |
|||
component: () => import('@/views/approvalList/index'), |
|||
hidden: true |
|||
}, |
|||
{ |
|||
path: '/rectification', |
|||
component: () => import('@/views/rectification/index'), |
|||
hidden: true |
|||
}, |
|||
{ |
|||
path: '/approval', |
|||
component: () => import('@/views/approval/index'), |
|||
hidden: true |
|||
}, |
|||
// {
|
|||
// path: '/details',
|
|||
// component: () => import('@/views/record/details'),
|
|||
// hidden: true
|
|||
// },
|
|||
{ |
|||
path: '/index', |
|||
component: () => import('@/views/index'), |
|||
hidden: true |
|||
}, |
|||
{ |
|||
path: '/404', |
|||
component: () => import('@/views/404'), |
|||
hidden: true |
|||
}, |
|||
{ |
|||
path: '/', |
|||
component: Layout, |
|||
redirect: '/qualitative', |
|||
children: [{ |
|||
path: 'qualitative', |
|||
name: 'Qualitative', |
|||
component: () => import('@/views/qualitative/index'), |
|||
meta: { title: '定性考核'} |
|||
}] |
|||
}, |
|||
{ |
|||
path: '/mete', |
|||
component: Layout, |
|||
redirect: '/mete', |
|||
children: [{ |
|||
path: 'mete', |
|||
name: 'Mete', |
|||
component: () => import('@/views/mete/index'), |
|||
meta: { title: '定量考核'} |
|||
}] |
|||
}, |
|||
{ |
|||
path: '/approvalData', |
|||
component: Layout, |
|||
redirect: '/approvalData', |
|||
children: [{ |
|||
path: 'approvalData', |
|||
name: 'approvalData', |
|||
component: () => import('@/views/approvalData/index'), |
|||
meta: { title: '审批记录'} |
|||
}] |
|||
}, |
|||
// {
|
|||
// path: '/',
|
|||
// component: Layout,
|
|||
// redirect: '/dashboard',
|
|||
// children: [{
|
|||
// path: 'dashboard',
|
|||
// name: 'Dashboard',
|
|||
// component: () => import('@/views/dashboard/index'),
|
|||
// meta: { title: '考核项目'}
|
|||
// }]
|
|||
// },
|
|||
// {
|
|||
// path: '/record',
|
|||
// component: Layout,
|
|||
// redirect: '/record',
|
|||
// children: [{
|
|||
// path: 'record',
|
|||
// name: 'Record',
|
|||
// component: () => import('@/views/record/index'),
|
|||
// meta: { title: '考核记录'}
|
|||
// }]
|
|||
// },
|
|||
{ |
|||
path: '/details', |
|||
component: Layout, |
|||
redirect: '/details', |
|||
children: [{ |
|||
path: 'details', |
|||
name: 'Details', |
|||
component: () => import('@/views/record/details'), |
|||
// meta: { title: '考核记录详情'}
|
|||
}] |
|||
}, |
|||
|
|||
|
|||
// {
|
|||
// path: '/example',
|
|||
// component: Layout,
|
|||
// redirect: '/example/table',
|
|||
// name: 'Example',
|
|||
// meta: { title: '表格', icon: 'el-icon-s-help' },
|
|||
// children: [
|
|||
// {
|
|||
// path: 'table',
|
|||
// name: 'Table',
|
|||
// component: () => import('@/views/table/index'),
|
|||
// meta: { title: 'Table', icon: 'table' }
|
|||
// },
|
|||
// {
|
|||
// path: 'tree',
|
|||
// name: 'Tree',
|
|||
// component: () => import('@/views/tree/index'),
|
|||
// meta: { title: 'Tree', icon: 'tree' }
|
|||
// }
|
|||
// ]
|
|||
// },
|
|||
|
|||
// {
|
|||
// path: '/form',
|
|||
// component: Layout,
|
|||
// children: [
|
|||
// {
|
|||
// path: 'index',
|
|||
// name: 'Form',
|
|||
// component: () => import('@/views/form/index'),
|
|||
// meta: { title: 'Form', icon: 'form' }
|
|||
// }
|
|||
// ]
|
|||
// },
|
|||
|
|||
// {
|
|||
// path: '/nested',
|
|||
// component: Layout,
|
|||
// redirect: '/nested/menu1',
|
|||
// name: 'Nested',
|
|||
// meta: {
|
|||
// title: 'Nested',
|
|||
// icon: 'nested'
|
|||
// },
|
|||
// children: [
|
|||
// {
|
|||
// path: 'menu1',
|
|||
// component: () => import('@/views/nested/menu1/index'), // Parent router-view
|
|||
// name: 'Menu1',
|
|||
// meta: { title: 'Menu1' },
|
|||
// children: [
|
|||
// {
|
|||
// path: 'menu1-1',
|
|||
// component: () => import('@/views/nested/menu1/menu1-1'),
|
|||
// name: 'Menu1-1',
|
|||
// meta: { title: 'Menu1-1' }
|
|||
// },
|
|||
// {
|
|||
// path: 'menu1-2',
|
|||
// component: () => import('@/views/nested/menu1/menu1-2'),
|
|||
// name: 'Menu1-2',
|
|||
// meta: { title: 'Menu1-2' },
|
|||
// children: [
|
|||
// {
|
|||
// path: 'menu1-2-1',
|
|||
// component: () => import('@/views/nested/menu1/menu1-2/menu1-2-1'),
|
|||
// name: 'Menu1-2-1',
|
|||
// meta: { title: 'Menu1-2-1' }
|
|||
// },
|
|||
// {
|
|||
// path: 'menu1-2-2',
|
|||
// component: () => import('@/views/nested/menu1/menu1-2/menu1-2-2'),
|
|||
// name: 'Menu1-2-2',
|
|||
// meta: { title: 'Menu1-2-2' }
|
|||
// }
|
|||
// ]
|
|||
// },
|
|||
// {
|
|||
// path: 'menu1-3',
|
|||
// component: () => import('@/views/nested/menu1/menu1-3'),
|
|||
// name: 'Menu1-3',
|
|||
// meta: { title: 'Menu1-3' }
|
|||
// }
|
|||
// ]
|
|||
// },
|
|||
// {
|
|||
// path: 'menu2',
|
|||
// component: () => import('@/views/nested/menu2/index'),
|
|||
// name: 'Menu2',
|
|||
// meta: { title: 'menu2' }
|
|||
// }
|
|||
// ]
|
|||
// },
|
|||
|
|||
// {
|
|||
// path: 'external-link',
|
|||
// component: Layout,
|
|||
// children: [
|
|||
// {
|
|||
// path: 'https://panjiachen.github.io/vue-element-admin-site/#/',
|
|||
// meta: { title: 'External Link', icon: 'link' }
|
|||
// }
|
|||
// ]
|
|||
// },
|
|||
|
|||
// 404 page must be placed at the end !!!
|
|||
{ path: '*', redirect: '/404', hidden: true } |
|||
] |
|||
|
|||
const createRouter = () => new Router({ |
|||
// mode: 'history', // require service support
|
|||
scrollBehavior: () => ({ y: 0 }), |
|||
routes: constantRoutes |
|||
}) |
|||
|
|||
const router = createRouter() |
|||
|
|||
// Detail see: https://github.com/vuejs/vue-router/issues/1234#issuecomment-357941465
|
|||
export function resetRouter() { |
|||
const newRouter = createRouter() |
|||
router.matcher = newRouter.matcher // reset router
|
|||
} |
|||
|
|||
export default router |
|||
@ -0,0 +1,16 @@ |
|||
module.exports = { |
|||
|
|||
title: '绩效考核', |
|||
|
|||
/** |
|||
* @type {boolean} true | false |
|||
* @description Whether fix the header |
|||
*/ |
|||
fixedHeader: false, |
|||
|
|||
/** |
|||
* @type {boolean} true | false |
|||
* @description Whether show the logo in sidebar |
|||
*/ |
|||
sidebarLogo: false |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
const getters = { |
|||
sidebar: state => state.app.sidebar, |
|||
device: state => state.app.device, |
|||
token: state => state.user.token, |
|||
avatar: state => state.user.avatar, |
|||
name: state => state.user.name |
|||
} |
|||
export default getters |
|||
@ -0,0 +1,19 @@ |
|||
import Vue from 'vue' |
|||
import Vuex from 'vuex' |
|||
import getters from './getters' |
|||
import app from './modules/app' |
|||
import settings from './modules/settings' |
|||
import user from './modules/user' |
|||
|
|||
Vue.use(Vuex) |
|||
|
|||
const store = new Vuex.Store({ |
|||
modules: { |
|||
app, |
|||
settings, |
|||
user |
|||
}, |
|||
getters |
|||
}) |
|||
|
|||
export default store |
|||
@ -0,0 +1,48 @@ |
|||
import Cookies from 'js-cookie' |
|||
|
|||
const state = { |
|||
sidebar: { |
|||
opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true, |
|||
withoutAnimation: false |
|||
}, |
|||
device: 'desktop' |
|||
} |
|||
|
|||
const mutations = { |
|||
TOGGLE_SIDEBAR: state => { |
|||
state.sidebar.opened = !state.sidebar.opened |
|||
state.sidebar.withoutAnimation = false |
|||
if (state.sidebar.opened) { |
|||
Cookies.set('sidebarStatus', 1) |
|||
} else { |
|||
Cookies.set('sidebarStatus', 0) |
|||
} |
|||
}, |
|||
CLOSE_SIDEBAR: (state, withoutAnimation) => { |
|||
Cookies.set('sidebarStatus', 0) |
|||
state.sidebar.opened = false |
|||
state.sidebar.withoutAnimation = withoutAnimation |
|||
}, |
|||
TOGGLE_DEVICE: (state, device) => { |
|||
state.device = device |
|||
} |
|||
} |
|||
|
|||
const actions = { |
|||
toggleSideBar({ commit }) { |
|||
commit('TOGGLE_SIDEBAR') |
|||
}, |
|||
closeSideBar({ commit }, { withoutAnimation }) { |
|||
commit('CLOSE_SIDEBAR', withoutAnimation) |
|||
}, |
|||
toggleDevice({ commit }, device) { |
|||
commit('TOGGLE_DEVICE', device) |
|||
} |
|||
} |
|||
|
|||
export default { |
|||
namespaced: true, |
|||
state, |
|||
mutations, |
|||
actions |
|||
} |
|||
@ -0,0 +1,32 @@ |
|||
import defaultSettings from '@/settings' |
|||
|
|||
const { showSettings, fixedHeader, sidebarLogo } = defaultSettings |
|||
|
|||
const state = { |
|||
showSettings: showSettings, |
|||
fixedHeader: fixedHeader, |
|||
sidebarLogo: sidebarLogo |
|||
} |
|||
|
|||
const mutations = { |
|||
CHANGE_SETTING: (state, { key, value }) => { |
|||
// eslint-disable-next-line no-prototype-builtins
|
|||
if (state.hasOwnProperty(key)) { |
|||
state[key] = value |
|||
} |
|||
} |
|||
} |
|||
|
|||
const actions = { |
|||
changeSetting({ commit }, data) { |
|||
commit('CHANGE_SETTING', data) |
|||
} |
|||
} |
|||
|
|||
export default { |
|||
namespaced: true, |
|||
state, |
|||
mutations, |
|||
actions |
|||
} |
|||
|
|||
@ -0,0 +1,119 @@ |
|||
import { login, logout, getInfo } from '@/api/user' |
|||
import { getToken, setToken, removeToken } from '@/utils/auth' |
|||
import { resetRouter } from '@/router' |
|||
import router from '@/router/index' |
|||
|
|||
const getDefaultState = () => { |
|||
return { |
|||
userInfo:{}, |
|||
key:'', |
|||
token: getToken(), |
|||
//token: getToken(),
|
|||
name: '', |
|||
avatar: '' |
|||
} |
|||
} |
|||
|
|||
const state = getDefaultState() |
|||
|
|||
const mutations = { |
|||
loginOut(state) { |
|||
state.userInfo = {} |
|||
state.token = '' |
|||
state.key = '' |
|||
router.push('/login') |
|||
}, |
|||
setUserInfo(state, userInfo) { |
|||
// 这里的 `state` 对象是模块的局部状态
|
|||
state.userInfo = userInfo |
|||
}, |
|||
setKey(state, key) { |
|||
// 这里的 `state` 对象是模块的局部状态
|
|||
state.key = key |
|||
}, |
|||
setToken(state, token) { |
|||
// 这里的 `state` 对象是模块的局部状态
|
|||
state.token = token |
|||
}, |
|||
RESET_STATE: (state) => { |
|||
Object.assign(state, getDefaultState()) |
|||
}, |
|||
SET_TOKEN: (state, token) => { |
|||
state.token = token |
|||
}, |
|||
SET_NAME: (state, name) => { |
|||
state.name = name |
|||
}, |
|||
SET_AVATAR: (state, avatar) => { |
|||
state.avatar = avatar |
|||
} |
|||
} |
|||
|
|||
const actions = { |
|||
// user login
|
|||
login({ commit }, userInfo) { |
|||
const { username, password } = userInfo |
|||
return new Promise((resolve, reject) => { |
|||
login({ username: username.trim(), password: password }).then(response => { |
|||
const { data } = response |
|||
commit('SET_TOKEN', data.token) |
|||
setToken(data.token) |
|||
resolve() |
|||
}).catch(error => { |
|||
reject(error) |
|||
}) |
|||
}) |
|||
}, |
|||
|
|||
// get user info
|
|||
getInfo({ commit, state }) { |
|||
return new Promise((resolve, reject) => { |
|||
getInfo(state.token).then(response => { |
|||
const { data } = response |
|||
|
|||
if (!data) { |
|||
return reject('Verification failed, please Login again.') |
|||
} |
|||
|
|||
const { name, avatar } = data |
|||
|
|||
commit('SET_NAME', name) |
|||
commit('SET_AVATAR', avatar) |
|||
resolve(data) |
|||
}).catch(error => { |
|||
reject(error) |
|||
}) |
|||
}) |
|||
}, |
|||
|
|||
// user logout
|
|||
logout({ commit, state }) { |
|||
return new Promise((resolve, reject) => { |
|||
logout(state.token).then(() => { |
|||
removeToken() // must remove token first
|
|||
resetRouter() |
|||
commit('RESET_STATE') |
|||
resolve() |
|||
}).catch(error => { |
|||
reject(error) |
|||
}) |
|||
}) |
|||
}, |
|||
|
|||
// remove token
|
|||
resetToken({ commit }) { |
|||
return new Promise(resolve => { |
|||
removeToken() // must remove token first
|
|||
commit('RESET_STATE') |
|||
resolve() |
|||
}) |
|||
} |
|||
} |
|||
|
|||
export default { |
|||
namespaced: true, |
|||
state, |
|||
mutations, |
|||
actions |
|||
} |
|||
|
|||
@ -0,0 +1,49 @@ |
|||
// cover some element-ui styles |
|||
|
|||
.el-breadcrumb__inner, |
|||
.el-breadcrumb__inner a { |
|||
font-weight: 400 !important; |
|||
} |
|||
|
|||
.el-upload { |
|||
input[type="file"] { |
|||
display: none !important; |
|||
} |
|||
} |
|||
|
|||
.el-upload__input { |
|||
display: none; |
|||
} |
|||
|
|||
|
|||
// to fixed https://github.com/ElemeFE/element/issues/2461 |
|||
.el-dialog { |
|||
transform: none; |
|||
left: 0; |
|||
position: relative; |
|||
margin: 0 auto; |
|||
} |
|||
|
|||
// refine element ui upload |
|||
.upload-container { |
|||
.el-upload { |
|||
width: 100%; |
|||
|
|||
.el-upload-dragger { |
|||
width: 100%; |
|||
height: 200px; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// dropdown |
|||
.el-dropdown-menu { |
|||
a { |
|||
display: block |
|||
} |
|||
} |
|||
|
|||
// to fix el-date-picker css style |
|||
.el-range-separator { |
|||
box-sizing: content-box; |
|||
} |
|||
@ -0,0 +1,65 @@ |
|||
@import './variables.scss'; |
|||
@import './mixin.scss'; |
|||
@import './transition.scss'; |
|||
@import './element-ui.scss'; |
|||
@import './sidebar.scss'; |
|||
|
|||
body { |
|||
height: 100%; |
|||
-moz-osx-font-smoothing: grayscale; |
|||
-webkit-font-smoothing: antialiased; |
|||
text-rendering: optimizeLegibility; |
|||
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; |
|||
} |
|||
|
|||
label { |
|||
font-weight: 700; |
|||
} |
|||
|
|||
html { |
|||
height: 100%; |
|||
box-sizing: border-box; |
|||
} |
|||
|
|||
#app { |
|||
height: 100%; |
|||
} |
|||
|
|||
*, |
|||
*:before, |
|||
*:after { |
|||
box-sizing: inherit; |
|||
} |
|||
|
|||
a:focus, |
|||
a:active { |
|||
outline: none; |
|||
} |
|||
|
|||
a, |
|||
a:focus, |
|||
a:hover { |
|||
cursor: pointer; |
|||
color: inherit; |
|||
text-decoration: none; |
|||
} |
|||
|
|||
div:focus { |
|||
outline: none; |
|||
} |
|||
|
|||
.clearfix { |
|||
&:after { |
|||
visibility: hidden; |
|||
display: block; |
|||
font-size: 0; |
|||
content: " "; |
|||
clear: both; |
|||
height: 0; |
|||
} |
|||
} |
|||
|
|||
// main-container global css |
|||
.app-container { |
|||
padding: 20px; |
|||
} |
|||
@ -0,0 +1,28 @@ |
|||
@mixin clearfix { |
|||
&:after { |
|||
content: ""; |
|||
display: table; |
|||
clear: both; |
|||
} |
|||
} |
|||
|
|||
@mixin scrollBar { |
|||
&::-webkit-scrollbar-track-piece { |
|||
background: #d3dce6; |
|||
} |
|||
|
|||
&::-webkit-scrollbar { |
|||
width: 6px; |
|||
} |
|||
|
|||
&::-webkit-scrollbar-thumb { |
|||
background: #99a9bf; |
|||
border-radius: 20px; |
|||
} |
|||
} |
|||
|
|||
@mixin relative { |
|||
position: relative; |
|||
width: 100%; |
|||
height: 100%; |
|||
} |
|||
@ -0,0 +1,226 @@ |
|||
#app { |
|||
|
|||
.main-container { |
|||
min-height: 100%; |
|||
transition: margin-left .28s; |
|||
margin-left: $sideBarWidth; |
|||
position: relative; |
|||
} |
|||
|
|||
.sidebar-container { |
|||
transition: width 0.28s; |
|||
width: $sideBarWidth !important; |
|||
background-color: $menuBg; |
|||
height: 100%; |
|||
position: fixed; |
|||
font-size: 0px; |
|||
top: 0; |
|||
bottom: 0; |
|||
left: 0; |
|||
z-index: 1001; |
|||
overflow: hidden; |
|||
|
|||
// reset element-ui css |
|||
.horizontal-collapse-transition { |
|||
transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out; |
|||
} |
|||
|
|||
.scrollbar-wrapper { |
|||
overflow-x: hidden !important; |
|||
} |
|||
|
|||
.el-scrollbar__bar.is-vertical { |
|||
right: 0px; |
|||
} |
|||
|
|||
.el-scrollbar { |
|||
height: 100%; |
|||
} |
|||
|
|||
&.has-logo { |
|||
.el-scrollbar { |
|||
height: calc(100% - 50px); |
|||
} |
|||
} |
|||
|
|||
.is-horizontal { |
|||
display: none; |
|||
} |
|||
|
|||
a { |
|||
display: inline-block; |
|||
width: 100%; |
|||
overflow: hidden; |
|||
} |
|||
|
|||
.svg-icon { |
|||
margin-right: 16px; |
|||
} |
|||
|
|||
.sub-el-icon { |
|||
margin-right: 12px; |
|||
margin-left: -2px; |
|||
} |
|||
|
|||
.el-menu { |
|||
border: none; |
|||
height: 100%; |
|||
width: 100% !important; |
|||
} |
|||
|
|||
// menu hover |
|||
.submenu-title-noDropdown, |
|||
.el-submenu__title { |
|||
&:hover { |
|||
background-color: $menuHover !important; |
|||
} |
|||
} |
|||
|
|||
.is-active>.el-submenu__title { |
|||
color: $subMenuActiveText !important; |
|||
} |
|||
|
|||
& .nest-menu .el-submenu>.el-submenu__title, |
|||
& .el-submenu .el-menu-item { |
|||
min-width: $sideBarWidth !important; |
|||
background-color: $subMenuBg !important; |
|||
|
|||
&:hover { |
|||
background-color: $subMenuHover !important; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.hideSidebar { |
|||
.sidebar-container { |
|||
width: 54px !important; |
|||
} |
|||
|
|||
.main-container { |
|||
margin-left: 54px; |
|||
} |
|||
|
|||
.submenu-title-noDropdown { |
|||
padding: 0 !important; |
|||
position: relative; |
|||
|
|||
.el-tooltip { |
|||
padding: 0 !important; |
|||
|
|||
.svg-icon { |
|||
margin-left: 20px; |
|||
} |
|||
|
|||
.sub-el-icon { |
|||
margin-left: 19px; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.el-submenu { |
|||
overflow: hidden; |
|||
|
|||
&>.el-submenu__title { |
|||
padding: 0 !important; |
|||
|
|||
.svg-icon { |
|||
margin-left: 20px; |
|||
} |
|||
|
|||
.sub-el-icon { |
|||
margin-left: 19px; |
|||
} |
|||
|
|||
.el-submenu__icon-arrow { |
|||
display: none; |
|||
} |
|||
} |
|||
} |
|||
|
|||
.el-menu--collapse { |
|||
.el-submenu { |
|||
&>.el-submenu__title { |
|||
&>span { |
|||
height: 0; |
|||
width: 0; |
|||
overflow: hidden; |
|||
visibility: hidden; |
|||
display: inline-block; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
.el-menu--collapse .el-menu .el-submenu { |
|||
min-width: $sideBarWidth !important; |
|||
} |
|||
|
|||
// mobile responsive |
|||
.mobile { |
|||
.main-container { |
|||
margin-left: 0px; |
|||
} |
|||
|
|||
.sidebar-container { |
|||
transition: transform .28s; |
|||
width: $sideBarWidth !important; |
|||
} |
|||
|
|||
&.hideSidebar { |
|||
.sidebar-container { |
|||
pointer-events: none; |
|||
transition-duration: 0.3s; |
|||
transform: translate3d(-$sideBarWidth, 0, 0); |
|||
} |
|||
} |
|||
} |
|||
|
|||
.withoutAnimation { |
|||
|
|||
.main-container, |
|||
.sidebar-container { |
|||
transition: none; |
|||
} |
|||
} |
|||
} |
|||
|
|||
// when menu collapsed |
|||
.el-menu--vertical { |
|||
&>.el-menu { |
|||
.svg-icon { |
|||
margin-right: 16px; |
|||
} |
|||
.sub-el-icon { |
|||
margin-right: 12px; |
|||
margin-left: -2px; |
|||
} |
|||
} |
|||
|
|||
.nest-menu .el-submenu>.el-submenu__title, |
|||
.el-menu-item { |
|||
&:hover { |
|||
// you can use $subMenuHover |
|||
background-color: $menuHover !important; |
|||
} |
|||
} |
|||
|
|||
// the scroll bar appears when the subMenu is too long |
|||
>.el-menu--popup { |
|||
max-height: 100vh; |
|||
overflow-y: auto; |
|||
|
|||
&::-webkit-scrollbar-track-piece { |
|||
background: #d3dce6; |
|||
} |
|||
|
|||
&::-webkit-scrollbar { |
|||
width: 6px; |
|||
} |
|||
|
|||
&::-webkit-scrollbar-thumb { |
|||
background: #99a9bf; |
|||
border-radius: 20px; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,48 @@ |
|||
// global transition css |
|||
|
|||
/* fade */ |
|||
.fade-enter-active, |
|||
.fade-leave-active { |
|||
transition: opacity 0.28s; |
|||
} |
|||
|
|||
.fade-enter, |
|||
.fade-leave-active { |
|||
opacity: 0; |
|||
} |
|||
|
|||
/* fade-transform */ |
|||
.fade-transform-leave-active, |
|||
.fade-transform-enter-active { |
|||
transition: all .5s; |
|||
} |
|||
|
|||
.fade-transform-enter { |
|||
opacity: 0; |
|||
transform: translateX(-30px); |
|||
} |
|||
|
|||
.fade-transform-leave-to { |
|||
opacity: 0; |
|||
transform: translateX(30px); |
|||
} |
|||
|
|||
/* breadcrumb transition */ |
|||
.breadcrumb-enter-active, |
|||
.breadcrumb-leave-active { |
|||
transition: all .5s; |
|||
} |
|||
|
|||
.breadcrumb-enter, |
|||
.breadcrumb-leave-active { |
|||
opacity: 0; |
|||
transform: translateX(20px); |
|||
} |
|||
|
|||
.breadcrumb-move { |
|||
transition: all .5s; |
|||
} |
|||
|
|||
.breadcrumb-leave-active { |
|||
position: absolute; |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
// sidebar |
|||
$menuText:#bfcbd9; |
|||
$menuActiveText:#409EFF; |
|||
$subMenuActiveText:#f4f4f5; //https://github.com/ElemeFE/element/issues/12951 |
|||
|
|||
$menuBg:#304156; |
|||
$menuHover:#263445; |
|||
|
|||
$subMenuBg:#1f2d3d; |
|||
$subMenuHover:#001528; |
|||
|
|||
$sideBarWidth: 210px; |
|||
|
|||
// the :export directive is the magic sauce for webpack |
|||
// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass |
|||
:export { |
|||
menuText: $menuText; |
|||
menuActiveText: $menuActiveText; |
|||
subMenuActiveText: $subMenuActiveText; |
|||
menuBg: $menuBg; |
|||
menuHover: $menuHover; |
|||
subMenuBg: $subMenuBg; |
|||
subMenuHover: $subMenuHover; |
|||
sideBarWidth: $sideBarWidth; |
|||
} |
|||
@ -0,0 +1,27 @@ |
|||
import Cookies from 'js-cookie' |
|||
|
|||
const TokenKey = 'vue_admin_template_token' |
|||
const KeyKey = 'vue_admin_template_key' |
|||
|
|||
export function getToken() { |
|||
return Cookies.get(TokenKey) |
|||
} |
|||
|
|||
export function setToken(token) { |
|||
return Cookies.set(TokenKey, token) |
|||
} |
|||
|
|||
export function removeToken() { |
|||
return Cookies.remove(TokenKey) |
|||
} |
|||
export function getKey() { |
|||
return Cookies.get(KeyKey) |
|||
} |
|||
|
|||
export function setKey(Key) { |
|||
return Cookies.set(KeyKey, Key) |
|||
} |
|||
|
|||
export function removeKey() { |
|||
return Cookies.remove(KeyKey) |
|||
} |
|||
@ -0,0 +1,30 @@ |
|||
// 对Date的扩展,将 Date 转化为指定格式的String
|
|||
// 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符,
|
|||
// 年(y)可以用 1-4 个占位符,毫秒(S)只能用 1 个占位符(是 1-3 位的数字)
|
|||
// (new Date()).Format("yyyy-MM-dd hh:mm:ss.S") ==> 2006-07-02 08:09:04.423
|
|||
// (new Date()).Format("yyyy-M-d h:m:s.S") ==> 2006-7-2 8:9:4.18
|
|||
// eslint-disable-next-line no-extend-native
|
|||
Date.prototype.Format = function(fmt) { |
|||
var o = { |
|||
'M+': this.getMonth() + 1, // 月份
|
|||
'd+': this.getDate(), // 日
|
|||
'h+': this.getHours(), // 小时
|
|||
'm+': this.getMinutes(), // 分
|
|||
's+': this.getSeconds(), // 秒
|
|||
'q+': Math.floor((this.getMonth() + 3) / 3), // 季度
|
|||
'S': this.getMilliseconds() // 毫秒
|
|||
} |
|||
if (/(y+)/.test(fmt)) { fmt = fmt.replace(RegExp.$1, (this.getFullYear() + '').substr(4 - RegExp.$1.length)) } |
|||
for (var k in o) { |
|||
if (new RegExp('(' + k + ')').test(fmt)) { fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length))) } |
|||
} |
|||
return fmt |
|||
} |
|||
|
|||
export function formatTimeToStr(times, pattern) { |
|||
var d = new Date(times).Format('yyyy-MM-dd hh:mm:ss') |
|||
if (pattern) { |
|||
d = new Date(times).Format(pattern) |
|||
} |
|||
return d.toLocaleString() |
|||
} |
|||
@ -0,0 +1,10 @@ |
|||
import defaultSettings from '@/settings' |
|||
|
|||
const title = defaultSettings.title || '绩效考核' |
|||
|
|||
export default function getPageTitle(pageTitle) { |
|||
if (pageTitle) { |
|||
return `${pageTitle} - ${title}` |
|||
} |
|||
return `${title}` |
|||
} |
|||
@ -0,0 +1,117 @@ |
|||
/** |
|||
* Created by PanJiaChen on 16/11/18. |
|||
*/ |
|||
|
|||
/** |
|||
* Parse the time to string |
|||
* @param {(Object|string|number)} time |
|||
* @param {string} cFormat |
|||
* @returns {string | null} |
|||
*/ |
|||
export function parseTime(time, cFormat) { |
|||
if (arguments.length === 0 || !time) { |
|||
return null |
|||
} |
|||
const format = cFormat || '{y}-{m}-{d} {h}:{i}:{s}' |
|||
let date |
|||
if (typeof time === 'object') { |
|||
date = time |
|||
} else { |
|||
if ((typeof time === 'string')) { |
|||
if ((/^[0-9]+$/.test(time))) { |
|||
// support "1548221490638"
|
|||
time = parseInt(time) |
|||
} else { |
|||
// support safari
|
|||
// https://stackoverflow.com/questions/4310953/invalid-date-in-safari
|
|||
time = time.replace(new RegExp(/-/gm), '/') |
|||
} |
|||
} |
|||
|
|||
if ((typeof time === 'number') && (time.toString().length === 10)) { |
|||
time = time * 1000 |
|||
} |
|||
date = new Date(time) |
|||
} |
|||
const formatObj = { |
|||
y: date.getFullYear(), |
|||
m: date.getMonth() + 1, |
|||
d: date.getDate(), |
|||
h: date.getHours(), |
|||
i: date.getMinutes(), |
|||
s: date.getSeconds(), |
|||
a: date.getDay() |
|||
} |
|||
const time_str = format.replace(/{([ymdhisa])+}/g, (result, key) => { |
|||
const value = formatObj[key] |
|||
// Note: getDay() returns 0 on Sunday
|
|||
if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] } |
|||
return value.toString().padStart(2, '0') |
|||
}) |
|||
return time_str |
|||
} |
|||
|
|||
/** |
|||
* @param {number} time |
|||
* @param {string} option |
|||
* @returns {string} |
|||
*/ |
|||
export function formatTime(time, option) { |
|||
if (('' + time).length === 10) { |
|||
time = parseInt(time) * 1000 |
|||
} else { |
|||
time = +time |
|||
} |
|||
const d = new Date(time) |
|||
const now = Date.now() |
|||
|
|||
const diff = (now - d) / 1000 |
|||
|
|||
if (diff < 30) { |
|||
return '刚刚' |
|||
} else if (diff < 3600) { |
|||
// less 1 hour
|
|||
return Math.ceil(diff / 60) + '分钟前' |
|||
} else if (diff < 3600 * 24) { |
|||
return Math.ceil(diff / 3600) + '小时前' |
|||
} else if (diff < 3600 * 24 * 2) { |
|||
return '1天前' |
|||
} |
|||
if (option) { |
|||
return parseTime(time, option) |
|||
} else { |
|||
return ( |
|||
d.getMonth() + |
|||
1 + |
|||
'月' + |
|||
d.getDate() + |
|||
'日' + |
|||
d.getHours() + |
|||
'时' + |
|||
d.getMinutes() + |
|||
'分' |
|||
) |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* @param {string} url |
|||
* @returns {Object} |
|||
*/ |
|||
export function param2Obj(url) { |
|||
const search = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ') |
|||
if (!search) { |
|||
return {} |
|||
} |
|||
const obj = {} |
|||
const searchArr = search.split('&') |
|||
searchArr.forEach(v => { |
|||
const index = v.indexOf('=') |
|||
if (index !== -1) { |
|||
const name = v.substring(0, index) |
|||
const val = v.substring(index + 1, v.length) |
|||
obj[name] = val |
|||
} |
|||
}) |
|||
return obj |
|||
} |
|||
@ -0,0 +1,88 @@ |
|||
import axios from 'axios' |
|||
import { MessageBox, Message } from 'element-ui' |
|||
import store from '@/store' |
|||
import { getToken,getKey } from '@/utils/auth' |
|||
|
|||
// create an axios instance
|
|||
const service = axios.create({ |
|||
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
|
|||
// withCredentials: true, // send cookies when cross-domain requests
|
|||
timeout: 5000 // request timeout
|
|||
}) |
|||
|
|||
// request interceptor
|
|||
service.interceptors.request.use( |
|||
config => { |
|||
// do something before request is sent
|
|||
|
|||
if (store.getters.token) { |
|||
// let each request carry token
|
|||
// ['X-Token'] is a custom headers key
|
|||
// please modify it according to the actual situation
|
|||
config.headers['user-token'] = getToken() |
|||
config.headers['user-key'] = getKey() |
|||
} |
|||
return config |
|||
}, |
|||
error => { |
|||
// do something with request error
|
|||
console.log(error) // for debug
|
|||
return Promise.reject(error) |
|||
} |
|||
) |
|||
|
|||
// response interceptor
|
|||
service.interceptors.response.use( |
|||
/** |
|||
* If you want to get http information such as headers or status |
|||
* Please return response => response |
|||
*/ |
|||
|
|||
/** |
|||
* Determine the request status by custom code |
|||
* Here is just an example |
|||
* You can also judge the status by HTTP Status Code |
|||
*/ |
|||
response => { |
|||
const res = response.data |
|||
|
|||
// if the custom code is not 20000, it is judged as an error.
|
|||
if (res.code !== 0) { |
|||
Message({ |
|||
message: res.msg || 'Error', |
|||
type: 'error', |
|||
duration: 5 * 1000 |
|||
}) |
|||
if(res.data.code === 3){ |
|||
store.commit('user/loginOut') |
|||
} |
|||
// 50008: Illegal token; 50012: Other clients logged in; 50014: Token expired;
|
|||
if (res.code === 50008 || res.code === 50012 || res.code === 50014) { |
|||
// to re-login
|
|||
MessageBox.confirm('You have been logged out, you can cancel to stay on this page, or log in again', 'Confirm logout', { |
|||
confirmButtonText: 'Re-Login', |
|||
cancelButtonText: 'Cancel', |
|||
type: 'warning' |
|||
}).then(() => { |
|||
store.dispatch('user/resetToken').then(() => { |
|||
location.reload() |
|||
}) |
|||
}) |
|||
} |
|||
return Promise.reject(new Error(res.msg || 'Error')) |
|||
} else { |
|||
return res |
|||
} |
|||
}, |
|||
error => { |
|||
console.log('err' + error) // for debug
|
|||
Message({ |
|||
message: error.msg, |
|||
type: 'error', |
|||
duration: 5 * 1000 |
|||
}) |
|||
return Promise.reject(error) |
|||
} |
|||
) |
|||
|
|||
export default service |
|||
@ -0,0 +1,20 @@ |
|||
/** |
|||
* Created by PanJiaChen on 16/11/18. |
|||
*/ |
|||
|
|||
/** |
|||
* @param {string} path |
|||
* @returns {Boolean} |
|||
*/ |
|||
export function isExternal(path) { |
|||
return /^(https?:|mailto:|tel:)/.test(path) |
|||
} |
|||
|
|||
/** |
|||
* @param {string} str |
|||
* @returns {Boolean} |
|||
*/ |
|||
export function validUsername(str) { |
|||
const valid_map = ['admin', 'editor'] |
|||
return valid_map.indexOf(str.trim()) >= 0 |
|||
} |
|||
@ -0,0 +1,228 @@ |
|||
<template> |
|||
<div class="wscn-http404-container"> |
|||
<div class="wscn-http404"> |
|||
<div class="pic-404"> |
|||
<img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404"> |
|||
<img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404"> |
|||
<img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404"> |
|||
<img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404"> |
|||
</div> |
|||
<div class="bullshit"> |
|||
<div class="bullshit__oops">OOPS!</div> |
|||
<div class="bullshit__info">All rights reserved |
|||
<a style="color:#20a0ff" href="https://wallstreetcn.com" target="_blank">wallstreetcn</a> |
|||
</div> |
|||
<div class="bullshit__headline">{{ message }}</div> |
|||
<div class="bullshit__info">Please check that the URL you entered is correct, or click the button below to return to the homepage.</div> |
|||
<a href="" class="bullshit__return-home">Back to home</a> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
|
|||
export default { |
|||
name: 'Page404', |
|||
computed: { |
|||
message() { |
|||
return 'The webmaster said that you can not enter this page...' |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.wscn-http404-container{ |
|||
transform: translate(-50%,-50%); |
|||
position: absolute; |
|||
top: 40%; |
|||
left: 50%; |
|||
} |
|||
.wscn-http404 { |
|||
position: relative; |
|||
width: 1200px; |
|||
padding: 0 50px; |
|||
overflow: hidden; |
|||
.pic-404 { |
|||
position: relative; |
|||
float: left; |
|||
width: 600px; |
|||
overflow: hidden; |
|||
&__parent { |
|||
width: 100%; |
|||
} |
|||
&__child { |
|||
position: absolute; |
|||
&.left { |
|||
width: 80px; |
|||
top: 17px; |
|||
left: 220px; |
|||
opacity: 0; |
|||
animation-name: cloudLeft; |
|||
animation-duration: 2s; |
|||
animation-timing-function: linear; |
|||
animation-fill-mode: forwards; |
|||
animation-delay: 1s; |
|||
} |
|||
&.mid { |
|||
width: 46px; |
|||
top: 10px; |
|||
left: 420px; |
|||
opacity: 0; |
|||
animation-name: cloudMid; |
|||
animation-duration: 2s; |
|||
animation-timing-function: linear; |
|||
animation-fill-mode: forwards; |
|||
animation-delay: 1.2s; |
|||
} |
|||
&.right { |
|||
width: 62px; |
|||
top: 100px; |
|||
left: 500px; |
|||
opacity: 0; |
|||
animation-name: cloudRight; |
|||
animation-duration: 2s; |
|||
animation-timing-function: linear; |
|||
animation-fill-mode: forwards; |
|||
animation-delay: 1s; |
|||
} |
|||
@keyframes cloudLeft { |
|||
0% { |
|||
top: 17px; |
|||
left: 220px; |
|||
opacity: 0; |
|||
} |
|||
20% { |
|||
top: 33px; |
|||
left: 188px; |
|||
opacity: 1; |
|||
} |
|||
80% { |
|||
top: 81px; |
|||
left: 92px; |
|||
opacity: 1; |
|||
} |
|||
100% { |
|||
top: 97px; |
|||
left: 60px; |
|||
opacity: 0; |
|||
} |
|||
} |
|||
@keyframes cloudMid { |
|||
0% { |
|||
top: 10px; |
|||
left: 420px; |
|||
opacity: 0; |
|||
} |
|||
20% { |
|||
top: 40px; |
|||
left: 360px; |
|||
opacity: 1; |
|||
} |
|||
70% { |
|||
top: 130px; |
|||
left: 180px; |
|||
opacity: 1; |
|||
} |
|||
100% { |
|||
top: 160px; |
|||
left: 120px; |
|||
opacity: 0; |
|||
} |
|||
} |
|||
@keyframes cloudRight { |
|||
0% { |
|||
top: 100px; |
|||
left: 500px; |
|||
opacity: 0; |
|||
} |
|||
20% { |
|||
top: 120px; |
|||
left: 460px; |
|||
opacity: 1; |
|||
} |
|||
80% { |
|||
top: 180px; |
|||
left: 340px; |
|||
opacity: 1; |
|||
} |
|||
100% { |
|||
top: 200px; |
|||
left: 300px; |
|||
opacity: 0; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
.bullshit { |
|||
position: relative; |
|||
float: left; |
|||
width: 300px; |
|||
padding: 30px 0; |
|||
overflow: hidden; |
|||
&__oops { |
|||
font-size: 32px; |
|||
font-weight: bold; |
|||
line-height: 40px; |
|||
color: #1482f0; |
|||
opacity: 0; |
|||
margin-bottom: 20px; |
|||
animation-name: slideUp; |
|||
animation-duration: 0.5s; |
|||
animation-fill-mode: forwards; |
|||
} |
|||
&__headline { |
|||
font-size: 20px; |
|||
line-height: 24px; |
|||
color: #222; |
|||
font-weight: bold; |
|||
opacity: 0; |
|||
margin-bottom: 10px; |
|||
animation-name: slideUp; |
|||
animation-duration: 0.5s; |
|||
animation-delay: 0.1s; |
|||
animation-fill-mode: forwards; |
|||
} |
|||
&__info { |
|||
font-size: 13px; |
|||
line-height: 21px; |
|||
color: grey; |
|||
opacity: 0; |
|||
margin-bottom: 30px; |
|||
animation-name: slideUp; |
|||
animation-duration: 0.5s; |
|||
animation-delay: 0.2s; |
|||
animation-fill-mode: forwards; |
|||
} |
|||
&__return-home { |
|||
display: block; |
|||
float: left; |
|||
width: 110px; |
|||
height: 36px; |
|||
background: #1482f0; |
|||
border-radius: 100px; |
|||
text-align: center; |
|||
color: #ffffff; |
|||
opacity: 0; |
|||
font-size: 14px; |
|||
line-height: 36px; |
|||
cursor: pointer; |
|||
animation-name: slideUp; |
|||
animation-duration: 0.5s; |
|||
animation-delay: 0.3s; |
|||
animation-fill-mode: forwards; |
|||
} |
|||
@keyframes slideUp { |
|||
0% { |
|||
transform: translateY(60px); |
|||
opacity: 0; |
|||
} |
|||
100% { |
|||
transform: translateY(0); |
|||
opacity: 1; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,67 @@ |
|||
<template> |
|||
<div> |
|||
<el-table :data="list" border style="width: 100%"> |
|||
<el-table-column prop="classTitle" label="考核纬度"></el-table-column> |
|||
<el-table-column prop="assessTitle" label="考核项目"></el-table-column> |
|||
<el-table-column prop="dutyTitle" label="具体职责"></el-table-column> |
|||
<el-table-column prop="extraPoints" label="加分"> |
|||
<template slot-scope="scope"> |
|||
{{scope.row.extraPoints/10}} |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="extraPointstext" label="加分说明"> |
|||
<template slot-scope="scope"> |
|||
{{scope.row.extraPointstext}} |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="deductPoints" label="扣分"> |
|||
<template slot-scope="scope"> |
|||
{{scope.row.deductPoints/10}} |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column prop="deductPointstext" label="扣分说明"> |
|||
<template slot-scope="scope"> |
|||
{{scope.row.deductPointstext}} |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column label="得分"> |
|||
<template slot-scope="scope"> |
|||
{{scope.row.score/10}} |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { lookdepartmentassessinfo } from '@/api/dutys' |
|||
export default { |
|||
data() { |
|||
return { |
|||
from:{ |
|||
id:"" |
|||
}, |
|||
list:[], |
|||
} |
|||
|
|||
}, |
|||
created() { |
|||
console.log('this.$route.query') |
|||
console.log(this.$route.query) |
|||
this.from.id=this.$route.query.id |
|||
this.getApprovalList() |
|||
}, |
|||
methods: { |
|||
async getApprovalList(){ |
|||
const res = await lookdepartmentassessinfo(this.from) |
|||
this.list=JSON.parse(JSON.stringify(res.data.dutyListMap)) |
|||
console.log(JSON.parse(JSON.stringify(res.data.dutyListMap))) |
|||
|
|||
}, |
|||
}, |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
|
|||
</style> |
|||
@ -0,0 +1,446 @@ |
|||
<template> |
|||
<!-- 审批流程列表 --> |
|||
<div class="dashboard-container"> |
|||
<div class="gva-search-box"> |
|||
<el-form ref="searchForm" :inline="true" :model="searchInfo"> |
|||
<el-form-item label="流程状态"> |
|||
<el-select v-model="searchInfo.state" clearable placeholder="请选择状态"> |
|||
<el-option :value=1 label="审批中">审批中</el-option> |
|||
<el-option :value=2 label="通过">通过</el-option> |
|||
<el-option :value=3 label="驳回">驳回</el-option> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item> |
|||
<el-button size="mini" type="primary" icon="el-icon-search" @click="onSubmit">查询</el-button> |
|||
<el-button size="mini" icon="el-icon-refresh" @click="onReset">重置</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</div> |
|||
<div class="gva-table-box"> |
|||
<!-- <div class="gva-btn-list"> |
|||
<el-button size="mini" type="primary" icon="el-icon-plus" @click="showAdd()">新增</el-button> |
|||
</div> --> |
|||
<el-table :data="tableData"> |
|||
<el-table-column align="left" label="审批编号" prop="outid"/> |
|||
<el-table-column align="left" label="审批名称" prop="tittle"/> |
|||
<el-table-column align="left" label="指标性质" prop="class"> |
|||
<template #default="scope"> |
|||
<div v-if="scope.row.class==1"> |
|||
定性考核 |
|||
</div> |
|||
<div v-if="scope.row.class==2"> |
|||
定量考核 |
|||
</div> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column align="left" label="当前节点" prop="node"/> |
|||
<el-table-column align="left" label="当前负责人" prop="currentpeo"/> |
|||
<el-table-column align="left" label="创建人" prop="founder"/> |
|||
<el-table-column align="left" label="审批状态" prop="condition"/> |
|||
<el-table-column align="left" label="审批结果" prop="result"/> |
|||
<el-table-column align="left" fixed="right" label="操作" width="200"> |
|||
<template #default="scope"> |
|||
<el-button |
|||
icon="el-icon-view" |
|||
size="small" |
|||
type="text" |
|||
@click="showCe(scope.row)" |
|||
>查看详情</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<div class="gva-pagination"> |
|||
<el-pagination |
|||
@size-change="handleSizeChange" |
|||
@current-change="handleCurrentChange" |
|||
:page-sizes="[10, 30, 50, 100]" |
|||
:page-size="searchInfo.pagesize" |
|||
layout="total, sizes, prev, pager, next, jumper" |
|||
:total="total"> |
|||
</el-pagination> |
|||
</div> |
|||
</div> |
|||
<!-- 定性侧边框 --> |
|||
<el-drawer |
|||
title="详情" |
|||
:visible.sync="drawer" |
|||
direction="rtl" |
|||
> |
|||
<el-card class="box-card" style="margin-bottom: 10px;"> |
|||
<p class="xiao">审批编号:{{xinglist.orderid}}</p> |
|||
<p class="da"> |
|||
{{xinglist.title}} |
|||
</p> |
|||
</el-card> |
|||
|
|||
<el-card class="box-card" style="margin-bottom: 10px;"> |
|||
<el-descriptions class="margin-top" :column="1"> |
|||
<el-descriptions-item label="考核纬度">{{xinglist.dimension}}</el-descriptions-item> |
|||
<el-descriptions-item label="考核指标">{{xinglist.target}}</el-descriptions-item> |
|||
<el-descriptions-item label="指标子类">{{xinglist.targetsun}}</el-descriptions-item> |
|||
<el-descriptions-item label="指标详情">{{xinglist.detailedtargent}}</el-descriptions-item> |
|||
<el-descriptions-item label="指标描述">{{xinglist.content}}</el-descriptions-item> |
|||
<el-descriptions-item label="操作">{{xinglist.reasoninfo}}</el-descriptions-item> |
|||
<el-descriptions-item label="原因">{{xinglist.reason}}</el-descriptions-item> |
|||
</el-descriptions> |
|||
</el-card> |
|||
<el-card class="box-card" v-for="(item,index) in xinglist.divresbil" :key="index" style="margin-bottom: 10px;"> |
|||
<div slot="header" class="clearfix"> |
|||
<span>责任划分</span> |
|||
</div> |
|||
<el-descriptions class="margin-top" :column="1"> |
|||
<el-descriptions-item label="责任类型">{{item.type}}</el-descriptions-item> |
|||
<el-descriptions-item label="姓名">{{item.username}}</el-descriptions-item> |
|||
<el-descriptions-item label="比重">{{item.weight}}</el-descriptions-item> |
|||
</el-descriptions> |
|||
</el-card> |
|||
<el-card class="box-card" v-for="(item,index) in xinglist.rectifmeasures" :key="index" style="margin-bottom: 10px;"> |
|||
<div slot="header" class="clearfix"> |
|||
<span>整改措施</span> |
|||
</div> |
|||
<el-descriptions class="margin-top" :column="1"> |
|||
<el-descriptions-item label="姓名">{{item.recname}}</el-descriptions-item> |
|||
<el-descriptions-item label="内容">{{item.reccont}}</el-descriptions-item> |
|||
<el-descriptions-item label="时间">{{item.timeval}}</el-descriptions-item> |
|||
</el-descriptions> |
|||
</el-card> |
|||
<el-card class="box-card"> |
|||
<el-steps direction="vertical" :active="xingbuzhou"> |
|||
<el-step v-for="(item,index) in xinglist.flowmapall" :key="index" :title="item.nodename" icon="el-icon-circle-check" > |
|||
<template slot="description"> |
|||
<p style="color: rgb(153,153,153);" v-for="(a,index) in item.userlist" > |
|||
<el-avatar style="margin-right: 5px;" shape="square" size="medium" :src="a.icon"></el-avatar> |
|||
{{a.workshopname}}-{{a.postname}}-{{a.name}} |
|||
<template v-if="a.log!=null"> |
|||
<el-tag v-if="a.log.state==2">通过</el-tag> |
|||
<el-tag v-if="a.log.state==1" type="info">未操作</el-tag> |
|||
<el-tag v-if="a.log.state==3" type="danger">驳回</el-tag> |
|||
<div>{{a.log.time}}</div> |
|||
</template> |
|||
</p> |
|||
</template> |
|||
</el-step> |
|||
</el-steps> |
|||
</el-card> |
|||
</el-drawer> |
|||
<!-- 定量侧边框 --> |
|||
<el-drawer |
|||
title="详情" |
|||
:visible.sync="dingliangdrawer" |
|||
direction="rtl" |
|||
> |
|||
<el-card class="box-card" style="margin-bottom: 10px;"> |
|||
<p class="xiao">审批编号:{{liangOutid}}</p> |
|||
<p class="da"> |
|||
{{lianglist.title}} |
|||
</p> |
|||
</el-card> |
|||
<el-card class="box-card" v-for="(item,index) in lianglist.List" :key="index" style="margin-bottom: 10px;"> |
|||
<el-descriptions class="margin-top" :column="1"> |
|||
<el-descriptions-item label="名称">{{item.title}}</el-descriptions-item> |
|||
<el-descriptions-item label="分值">{{item.Score}}{{item.unit}}</el-descriptions-item> |
|||
<el-descriptions-item label="说明">{{item.content}}</el-descriptions-item> |
|||
</el-descriptions> |
|||
</el-card> |
|||
<el-card class="box-card"> |
|||
<el-steps direction="vertical" :active="liangbuzhou"> |
|||
<el-step v-for="(item,index) in lianglist.flowall" :key="index" :title="item.nodename" icon="el-icon-circle-check" > |
|||
<template slot="description"> |
|||
<p style="color: rgb(153,153,153);" v-for="(a,index) in item.userlist" > |
|||
<el-avatar style="margin-right: 5px;" shape="square" size="medium" :src="a.icon"></el-avatar> |
|||
{{a.workshopname}}-{{a.postname}}-{{a.name}} |
|||
<template v-if="a.log!=null"> |
|||
<el-tag v-if="a.log.state==2">通过</el-tag> |
|||
<el-tag v-if="a.log.state==1" type="info">未操作</el-tag> |
|||
<el-tag v-if="a.log.state==3" type="danger">驳回</el-tag> |
|||
<div>{{a.log.time}}</div> |
|||
</template> |
|||
</p> |
|||
</template> |
|||
</el-step> |
|||
</el-steps> |
|||
</el-card> |
|||
</el-drawer> |
|||
|
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { seeflowlog,lookrationkscoreflow,lookdutkscoreflow } from '@/api/dutys' |
|||
export default { |
|||
name: 'Dashboard', |
|||
data() { |
|||
return { |
|||
liangOutid:'', |
|||
lianglist:[], |
|||
xinglist:[], |
|||
xingbuzhou:0, |
|||
liangbuzhou:0, |
|||
// 侧边栏控制 |
|||
drawer: false, |
|||
dingliangdrawer:false, |
|||
// 查询详情的数据 |
|||
editFrom:{}, |
|||
// 修改状态提交数据 |
|||
switchFrom:{}, |
|||
// 删除数据提交 |
|||
deleFrom:{}, |
|||
// 编辑时数据 |
|||
editAdd:{}, |
|||
assessList:{}, |
|||
// 添加数据 |
|||
form:{ |
|||
type:1, |
|||
}, |
|||
// 弹窗变量 |
|||
dialogFormVisible:false, |
|||
// 修改弹窗 |
|||
editDialogFormVisible:false, |
|||
total: 0, |
|||
tableData:[ |
|||
|
|||
], |
|||
// 条件查询变量 |
|||
searchInfo: { |
|||
page: 1, |
|||
pagesize: 10 |
|||
}, |
|||
// 条件查询变量 |
|||
abc:{ |
|||
aaa:"111", |
|||
bbb:"222" |
|||
}, |
|||
// 添加时验证规则 |
|||
rules: { |
|||
title: [{ required: true, message: '请输入名称', trigger: 'blur' }], |
|||
}, |
|||
editRules:{ |
|||
title: [{ required: true, message: '请输入名称', trigger: 'blur' }], |
|||
} |
|||
} |
|||
}, |
|||
created() { |
|||
console.log(this.$store.state.user.token) |
|||
if (this.$store.state.user.token=='') { |
|||
this.$router.push('/login') |
|||
} |
|||
// 页面渲染时获取初始数据 |
|||
this.getDataList() |
|||
}, |
|||
methods: { |
|||
// 点击侧边栏操作 |
|||
showCe(row){ |
|||
if (row.class==1) { |
|||
// 定性 |
|||
this.getdingxingData(row.outid) |
|||
this.drawer=true |
|||
|
|||
}else if (row.class==2) { |
|||
// 定量 |
|||
this.liangOutid=row.outid |
|||
this.getdingliangData(row.outid) |
|||
this.dingliangdrawer=true |
|||
} |
|||
|
|||
}, |
|||
// 获取定性考核详情 |
|||
async getdingxingData(outid){ |
|||
const from = { |
|||
outid:outid |
|||
} |
|||
const res = await lookdutkscoreflow(from) |
|||
this.xinglist=res.data |
|||
this.xinglist.flowmapall.forEach(element => { |
|||
if (element.state==2) { |
|||
this.xingbuzhou=this.xingbuzhou+1 |
|||
} |
|||
}); |
|||
console.log(this.list) |
|||
}, |
|||
// 获取定量考核详情 |
|||
async getdingliangData(outId){ |
|||
const from = { |
|||
outid:outId |
|||
} |
|||
const res = await lookrationkscoreflow(from) |
|||
this.lianglist=res.data |
|||
this.lianglist.flowall.forEach(element => { |
|||
if (element.state==2) { |
|||
this.liangbuzhou=this.liangbuzhou+1 |
|||
} |
|||
}); |
|||
console.log(this.list) |
|||
}, |
|||
// 删除操作 |
|||
//删除操作 |
|||
async deleteOperate(row) { |
|||
this.$confirm('此操作将永久删除, 是否继续?', '提示', { |
|||
confirmButtonText: '确定', |
|||
cancelButtonText: '取消', |
|||
type: 'warning' |
|||
}) |
|||
.then(async() => { |
|||
this.deleFrom.state=3; |
|||
this.deleFrom.outid=row.outId; |
|||
const res = await statedutyclass(this.deleFrom) |
|||
if (res.code === 0) { |
|||
this.$message({ |
|||
type: 'success', |
|||
message: '删除成功!' |
|||
}) |
|||
|
|||
this.getDataList() |
|||
} |
|||
}) |
|||
}, |
|||
// 新增按钮 |
|||
showAdd(){ |
|||
this.dialogFormVisible=true; |
|||
console.log(this.dialogFormVisible) |
|||
}, |
|||
// 编辑按钮 |
|||
async showEdit(row){ |
|||
this.editFrom.outid=row.outId |
|||
const res = await getdutyclassinfo(this.editFrom) |
|||
this.editAdd = res.data |
|||
this.editDialogFormVisible=true; |
|||
|
|||
}, |
|||
// 开关状态监听 |
|||
async changeVal(val,id){ |
|||
console.log(val) |
|||
this.switchFrom.outid=id |
|||
if (val==1) { |
|||
this.switchFrom.state=1; |
|||
const res = await statedutyclass(this.switchFrom) |
|||
if (res.code === 0) { |
|||
this.$message({ |
|||
type: 'success', |
|||
message: '修改状态成功', |
|||
showClose: true |
|||
}) |
|||
this.getDataList() |
|||
} |
|||
} else { |
|||
this.switchFrom.state=2; |
|||
const res = await statedutyclass(this.switchFrom) |
|||
if (res.code === 0) { |
|||
this.$message({ |
|||
type: 'success', |
|||
message: '修改状态成功', |
|||
showClose: true |
|||
}) |
|||
this.getDataList() |
|||
} |
|||
} |
|||
}, |
|||
// 重置搜索条件 |
|||
onReset() { |
|||
this.searchInfo = {} |
|||
}, |
|||
// 条件搜索 |
|||
onSubmit() { |
|||
this.page = 1 |
|||
this.pageSize = 10 |
|||
this.getDataList() |
|||
}, |
|||
// 日期时间戳转日期格式 |
|||
formatDate(nS) { |
|||
return new Date(parseInt(nS) * 1000).toLocaleString().replace(/:\d{1,2}$/,' '); |
|||
}, |
|||
|
|||
// 提交按钮 |
|||
async enterDialog(){ |
|||
|
|||
this.$refs.addForm.validate(async valid => { |
|||
if (valid) { |
|||
const res = await adddutyclass(this.form) |
|||
if (res.code === 0) { |
|||
this.$message({ |
|||
type: 'success', |
|||
message: '添加成功', |
|||
showClose: true |
|||
}) |
|||
} |
|||
this.getDataList(); |
|||
this.closeDialog(); |
|||
} |
|||
}) |
|||
}, |
|||
|
|||
// 编辑提交按钮 |
|||
async editEnterDialog(){ |
|||
this.$refs.editForm.validate(async valid => { |
|||
if (valid) { |
|||
const res = await eitedutyclassinfo(this.editAdd) |
|||
if (res.code === 0) { |
|||
this.$message({ |
|||
type: 'success', |
|||
message: '编辑成功', |
|||
showClose: true |
|||
}) |
|||
} |
|||
this.getDataList(); |
|||
this.editCloseDialog(); |
|||
} |
|||
}) |
|||
}, |
|||
// 添加框关闭 |
|||
closeDialog() { |
|||
console.log("closeDialog") |
|||
this.initForm() |
|||
this.dialogFormVisible = false |
|||
}, |
|||
// 修改框关闭 |
|||
editCloseDialog() { |
|||
this.editInitForm() |
|||
this.editDialogFormVisible = false |
|||
}, |
|||
// 添加重置表单 |
|||
initForm() { |
|||
console.log("initForm") |
|||
this.$refs.addForm.resetFields() |
|||
this.form = {} |
|||
console.log(this.form) |
|||
}, |
|||
// 修改重置表单 |
|||
editInitForm() { |
|||
this.$refs.editForm.resetFields() |
|||
this.editAdd = {} |
|||
}, |
|||
// 改变pageSize |
|||
handleSizeChange(val) { |
|||
this.searchInfo.pagesize=val |
|||
this.getDataList(this.searchInfo) |
|||
}, |
|||
// 改变page |
|||
handleCurrentChange(val) { |
|||
this.searchInfo.page=val |
|||
this.getDataList(this.searchInfo) |
|||
}, |
|||
// 获取初始数据 |
|||
async getDataList() { |
|||
const res = await seeflowlog(this.searchInfo) |
|||
this.tableData = res.data.list |
|||
this.total = res.data.total |
|||
this.searchInfo.page = res.data.page |
|||
this.searchInfo.pagesize = res.data.pageSize |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.el-drawer__body{ |
|||
padding: 10px !important; |
|||
} |
|||
.dashboard { |
|||
&-container { |
|||
margin: 30px; |
|||
} |
|||
&-text { |
|||
font-size: 30px; |
|||
line-height: 46px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,409 @@ |
|||
<template> |
|||
<div style="background-color:rgb(242,244,246)"> |
|||
<!-- <div class="p2" v-if="cardShow">定性考核审批</div> --> |
|||
<div :style="'width:' + bianKuan + '%;margin: 0 auto;padding: 5px;'"> |
|||
<el-card class="box-card" style="margin-bottom: 10px;"> |
|||
<p class="xiao">审批编号:{{list.orderid}}</p> |
|||
<p class="da"> |
|||
{{list.title}} |
|||
</p> |
|||
</el-card> |
|||
<el-card class="box-card" v-if="carddianShow" style="margin-bottom: 10px;"> |
|||
<el-descriptions class="margin-top" :column="3" border> |
|||
<el-descriptions-item> |
|||
<template slot="label"> |
|||
考核纬度 |
|||
</template> |
|||
{{list.dimension}} |
|||
</el-descriptions-item> |
|||
<el-descriptions-item> |
|||
<template slot="label"> |
|||
考核指标 |
|||
</template> |
|||
{{list.target}} |
|||
</el-descriptions-item> |
|||
<el-descriptions-item> |
|||
<template slot="label"> |
|||
指标子类 |
|||
</template> |
|||
{{list.targetsun}} |
|||
</el-descriptions-item> |
|||
<el-descriptions-item> |
|||
<template slot="label"> |
|||
指标详情 |
|||
</template> |
|||
{{list.detailedtargent}} |
|||
</el-descriptions-item> |
|||
<el-descriptions-item> |
|||
<template slot="label"> |
|||
指标描述 |
|||
</template> |
|||
{{list.content}} |
|||
</el-descriptions-item> |
|||
<el-descriptions-item> |
|||
<template slot="label"> |
|||
操作 |
|||
</template> |
|||
{{list.reasoninfo}} |
|||
</el-descriptions-item> |
|||
<el-descriptions-item> |
|||
<template slot="label"> |
|||
原因 |
|||
</template> |
|||
{{list.reason}} |
|||
</el-descriptions-item> |
|||
</el-descriptions> |
|||
</el-card> |
|||
<el-card class="box-card" v-if="cardShow" style="margin-bottom: 10px;"> |
|||
<el-descriptions class="margin-top" :column="1"> |
|||
<el-descriptions-item label="考核纬度">{{list.dimension}}</el-descriptions-item> |
|||
<el-descriptions-item label="考核指标">{{list.target}}</el-descriptions-item> |
|||
<el-descriptions-item label="考核项目">{{list.targetsun}}</el-descriptions-item> |
|||
<el-descriptions-item label="考核内容">{{list.detailedtargent}}</el-descriptions-item> |
|||
<el-descriptions-item label="考核标准">{{list.content}}</el-descriptions-item> |
|||
<el-descriptions-item label="操作">{{list.reasoninfo}}</el-descriptions-item> |
|||
<el-descriptions-item label="考核原因">{{list.reason}}</el-descriptions-item> |
|||
</el-descriptions> |
|||
</el-card> |
|||
<el-card class="box-card" v-for="(item,index) in list.divresbil" :key="index" style="margin-bottom: 10px;"> |
|||
<div slot="header" class="clearfix"> |
|||
<span>责任划分</span> |
|||
</div> |
|||
<el-descriptions class="margin-top" :column="1"> |
|||
<el-descriptions-item label="责任类型">{{item.type}}</el-descriptions-item> |
|||
<el-descriptions-item label="姓名">{{item.username}}</el-descriptions-item> |
|||
<el-descriptions-item label="比重">{{item.weight}}</el-descriptions-item> |
|||
</el-descriptions> |
|||
</el-card> |
|||
<el-card class="box-card" v-for="(item,index) in list.rectifmeasures" :key="index" style="margin-bottom: 10px;"> |
|||
<div slot="header" class="clearfix"> |
|||
<span>整改措施</span> |
|||
</div> |
|||
<el-descriptions class="margin-top" :column="1"> |
|||
<el-descriptions-item label="姓名">{{item.recname}}</el-descriptions-item> |
|||
<el-descriptions-item label="内容">{{item.reccont}}</el-descriptions-item> |
|||
<el-descriptions-item label="时间">{{item.timeval}}</el-descriptions-item> |
|||
</el-descriptions> |
|||
</el-card> |
|||
<!-- <el-table |
|||
:data="list.divresbil" |
|||
border |
|||
style="width: 100%"> |
|||
<el-table-column |
|||
prop="type" |
|||
label="责任类型"> |
|||
</el-table-column> |
|||
<el-table-column |
|||
prop="username" |
|||
label="姓名"> |
|||
</el-table-column> |
|||
<el-table-column |
|||
prop="weight" |
|||
label="比重"> |
|||
</el-table-column> |
|||
</el-table> --> |
|||
<!-- <div v-for="(item,index) in list.TechnologicalProcess"> |
|||
<el-descriptions class="margin-top" :column="3" border> |
|||
<el-descriptions-item> |
|||
<template slot="label"> |
|||
节点 |
|||
</template> |
|||
{{item.groupname}} |
|||
</el-descriptions-item> |
|||
<el-descriptions-item> |
|||
<template slot="label"> |
|||
步骤 |
|||
</template> |
|||
{{item.step}} |
|||
</el-descriptions-item> |
|||
<el-descriptions-item> |
|||
<template slot="label"> |
|||
状态 |
|||
</template> |
|||
<div v-if="item.state==1"> |
|||
未操作 |
|||
</div> |
|||
<div v-if="item.state==2"> |
|||
已操作 |
|||
</div> |
|||
</el-descriptions-item> |
|||
|
|||
</el-descriptions> |
|||
<el-table |
|||
:data="item.userlist" |
|||
border |
|||
style="width: 100%"> |
|||
<el-table-column |
|||
prop="name" |
|||
label="姓名"> |
|||
</el-table-column> |
|||
<el-table-column |
|||
prop="istrue" |
|||
label="操作"> |
|||
<template #default="scope"> |
|||
<div v-if="scope.row.istrue==1"><img width="20px" src="../../assets/duihao.png"></div> |
|||
<div v-if="scope.row.istrue==0"></div> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column |
|||
prop="timeval" |
|||
label="操作时间"> |
|||
</el-table-column> |
|||
</el-table> |
|||
</div> --> |
|||
<!-- --> |
|||
<el-card class="box-card"> |
|||
|
|||
<el-steps direction="vertical" :active="buzhou"> |
|||
<el-step v-for="(item,index) in list.flowmapall" :key="index" :title="item.nodename" icon="el-icon-circle-check" > |
|||
<template slot="description"> |
|||
<div style="color: rgb(153,153,153);" v-for="(a,userlistIndex) in item.userlist" :key="userlistIndex"> |
|||
<el-row> |
|||
<el-col :span="2"> |
|||
<el-badge is-dot type="primary "> |
|||
<el-avatar style="margin-right: 5px;" shape="square" size="small" :src="a.icon"></el-avatar> |
|||
</el-badge> |
|||
</el-col> |
|||
<el-col :span="22"> |
|||
{{a.workshopname}}-{{a.postname}}-{{a.name}} |
|||
<el-row> |
|||
<div v-for="(i,logIndex) in a.log" :key="logIndex"> |
|||
<div class="left" v-if="i.state==2">已同意 · </div> |
|||
<div class="left" v-if="i.state==1" type="info">未操作 · </div> |
|||
<div class="left" v-if="i.state==3" type="danger">驳回 · </div> |
|||
<div class="left">{{i.time}}</div> |
|||
</div> |
|||
</el-row> |
|||
</el-col> |
|||
</el-row> |
|||
|
|||
<!-- {{userlist.log}} --> |
|||
|
|||
<!-- <div class="left"> |
|||
<el-avatar style="margin-right: 5px;" shape="square" size="small" :src="a.icon"></el-avatar> |
|||
</div> |
|||
|
|||
|
|||
<div class="left">{{a.workshopname}}-{{a.postname}}-{{a.name}} </div> |
|||
|
|||
|
|||
<div class="left" v-for="(i,logIndex) in a.log"> |
|||
<el-tag v-if="i.state==2">通过</el-tag> |
|||
<el-tag v-if="i.state==1" type="info">未操作</el-tag> |
|||
<el-tag v-if="i.state==3" type="danger">驳回</el-tag> |
|||
<div>{{i.time}}</div> |
|||
</div> --> |
|||
|
|||
|
|||
|
|||
<!-- <template v-if="a.log!=null"> |
|||
<div v-for="(i,logIndex) in a.log"> |
|||
<el-tag v-if="i.state==2">通过</el-tag> |
|||
<el-tag v-if="i.state==1" type="info">未操作</el-tag> |
|||
<el-tag v-if="i.state==3" type="danger">驳回</el-tag> |
|||
<div>{{i.time}}</div> |
|||
</div> |
|||
</template> --> |
|||
|
|||
<!-- <el-tag v-if="a.log!=null||a.log.state==1" type="info">未操作</el-tag> |
|||
<el-tag v-if="a.log!=null||a.log.state==3" type="danger">驳回</el-tag> --> |
|||
<!-- <div>{{}}</div> --> |
|||
</div> |
|||
</template> |
|||
</el-step> |
|||
</el-steps> |
|||
</el-card> |
|||
|
|||
<!-- <el-table |
|||
:data="list.rectifmeasures" |
|||
border |
|||
style="width: 100%"> |
|||
<el-table-column |
|||
prop="recname" |
|||
label="姓名"> |
|||
</el-table-column> |
|||
<el-table-column |
|||
prop="reccont" |
|||
label="操作"> |
|||
</el-table-column> |
|||
<el-table-column |
|||
prop="timeval" |
|||
label="时间"> |
|||
</el-table-column> |
|||
</el-table> --> |
|||
|
|||
</div> |
|||
|
|||
|
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { getToken, setToken, removeToken,setKey } from '@/utils/auth' |
|||
import { getgroupuser,adddivisionresponsibility,addcorrectivemeasures,lookdutkscoreflow } from '@/api/dutys' |
|||
export default { |
|||
data() { |
|||
return{ |
|||
// 步骤显示 |
|||
buzhou:0, |
|||
carddianShow:false, |
|||
cardShow:false, |
|||
// 数据列表 |
|||
list:[], |
|||
// 选择员工配置项 |
|||
userProps: { |
|||
value: "id", |
|||
label: "name", |
|||
children: "groupUser", |
|||
emitPath:false, |
|||
multiple: false |
|||
}, |
|||
grouplistBackup:[], |
|||
form:{ |
|||
outid:'', |
|||
}, |
|||
tableData:[ |
|||
{ |
|||
type:1,//类型 |
|||
userkey:'',//人员 |
|||
weight:''//比重 |
|||
}, |
|||
], |
|||
} |
|||
}, |
|||
created () { |
|||
if ((navigator.userAgent.match(/(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i))) { |
|||
setToken(this.$route.query.token) |
|||
setKey(this.$route.query.key) |
|||
if (getToken()=='') { |
|||
window.location.href = 'https://www.hxgk.group/jumpapiurl/?url=http://new.hxgk.group&controll=approvalList&id='+this.$route.query.id; |
|||
} |
|||
if (typeof this.$route.query.token === 'undefined') { |
|||
window.location.href = 'https://www.hxgk.group/jumpapiurl/?url=http://new.hxgk.group&controll=approvalList&id='+this.$route.query.id; |
|||
} |
|||
}else{ |
|||
if (sessionStorage.getItem('userinfo')==null) { |
|||
this.$router.push('/dingxingLogin?id='+this.$route.query.id) |
|||
} |
|||
if (sessionStorage.getItem('userinfo')==undefined) { |
|||
this.$router.push('/dingxingLogin?id='+this.$route.query.id) |
|||
} |
|||
if (sessionStorage.getItem('userinfo')=='') { |
|||
this.$router.push('/dingxingLogin?id='+this.$route.query.id) |
|||
} |
|||
if (this.$store.state.user.token=='') { |
|||
this.$router.push('/dingxingLogin?id='+this.$route.query.id) |
|||
} |
|||
if (this.$store.state.user.token==null) { |
|||
this.$router.push('/dingxingLogin?id='+this.$route.query.id) |
|||
} |
|||
if (this.$store.state.user.token===undefined) { |
|||
this.$router.push('/dingxingLogin?id='+this.$route.query.id) |
|||
} |
|||
if (typeof this.$store.state.user.token=="undefined") { |
|||
this.$router.push('/dingxingLogin?id='+this.$route.query.id) |
|||
} |
|||
} |
|||
this.form.outid=this.$route.query.id |
|||
|
|||
|
|||
if (document.body.clientWidth<1000) { |
|||
this.bianKuan=100 |
|||
this.carddianShow=false |
|||
this.cardShow=true |
|||
}else{ |
|||
this.bianKuan=40 |
|||
this.carddianShow=true |
|||
this.cardShow=false |
|||
} |
|||
this.getData() |
|||
}, |
|||
methods: { |
|||
// 获取数据 |
|||
async getData(){ |
|||
const res = await lookdutkscoreflow(this.form) |
|||
this.list=res.data |
|||
this.list.flowmapall.forEach(element => { |
|||
if (element.state==2) { |
|||
this.buzhou=this.buzhou+1 |
|||
} |
|||
}); |
|||
this.list.flowmapall.forEach(function(element) { |
|||
if (element.userlist!=null) { |
|||
element.userlist.forEach(function(iteam){ |
|||
if (iteam.log==null) { |
|||
iteam.log=[{ |
|||
state: 0, |
|||
time: "" |
|||
}] |
|||
} |
|||
}) |
|||
} |
|||
}); |
|||
console.log("this.list") |
|||
console.log(this.list) |
|||
}, |
|||
// 提交数据 |
|||
async tijiao(){ |
|||
console.log(this.tableData) |
|||
const res = await addcorrectivemeasures(this.form) |
|||
if (res.code==0) { |
|||
this.$message({ |
|||
type: 'success', |
|||
message: '提交成功', |
|||
showClose: true |
|||
}) |
|||
} |
|||
}, |
|||
// 删除行 |
|||
deleteRulesList(row){ |
|||
this.tableData.splice(row.$index,1); |
|||
}, |
|||
// 数组加行 |
|||
jiaArr(){ |
|||
this.tableData.push({ |
|||
type:'',//类型 |
|||
userkey:'',//人员 |
|||
weight:''//比重 |
|||
}) |
|||
}, |
|||
// 获取员工列表 |
|||
async getSystemadminlist(){ |
|||
const res = await getgroupuser() |
|||
this.grouplistBackup=res.data.list |
|||
}, |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.left{ |
|||
float: left; |
|||
} |
|||
.xiao{ |
|||
color: rgb(174,174,174); |
|||
} |
|||
.da{ |
|||
font-size: 22px; |
|||
font-weight:bold; |
|||
} |
|||
.form{ |
|||
width: 100%; |
|||
margin: 0 auto; |
|||
} |
|||
.p{ |
|||
margin-bottom: 10px !important; |
|||
margin-top: 20px !important; |
|||
width: 235px; |
|||
// font-size: 30px; |
|||
// font-weight:bold; |
|||
margin: 0 auto; |
|||
} |
|||
.p2{ |
|||
margin-bottom: 10px !important; |
|||
margin-top: 20px !important; |
|||
width: 270px; |
|||
font-size: 24px; |
|||
margin: 0 auto; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,150 @@ |
|||
<template> |
|||
<div> |
|||
<el-tabs tab-position="top" style="" stretch> |
|||
<el-tab-pane label="任务首页"> |
|||
<div style="width:70%;height:600px"> |
|||
|
|||
</div> |
|||
</el-tab-pane> |
|||
<el-tab-pane label="修改密码"> |
|||
<div style="width:18%;margin:100px auto;"> |
|||
<el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm"> |
|||
<el-form-item label="原密码" prop="age"> |
|||
<el-input type="password" v-model.number="ruleForm.age"></el-input> |
|||
</el-form-item> |
|||
<el-form-item label="新密码" prop="pass"> |
|||
<el-input type="password" v-model="ruleForm.pass" autocomplete="off"></el-input> |
|||
</el-form-item> |
|||
<el-form-item label="确认密码" prop="checkPass"> |
|||
<el-input type="password" v-model="ruleForm.checkPass" autocomplete="off"></el-input> |
|||
</el-form-item> |
|||
|
|||
<el-form-item> |
|||
<el-button type="primary" @click="submitForm('ruleForm')">提交</el-button> |
|||
<el-button @click="resetForm('ruleForm')">重置</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</div> |
|||
|
|||
</el-tab-pane> |
|||
<el-tab-pane label="余额提现"> |
|||
<div style="width:18%;margin:100px auto;"> |
|||
<el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm"> |
|||
<el-form-item label="可用余额" prop="age"> |
|||
0.06 |
|||
</el-form-item> |
|||
<el-form-item label="体现金额" prop="pass"> |
|||
<el-input v-model.number="ruleForm.pass" autocomplete="off"></el-input> |
|||
</el-form-item> |
|||
|
|||
<el-form-item> |
|||
|
|||
<el-button type="primary" @click="submitForm('ruleForm')">提交</el-button> |
|||
<el-button @click="resetForm('ruleForm')">重置</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</div> |
|||
</el-tab-pane> |
|||
<el-tab-pane label="账户绑定"> |
|||
<div style="width:18%;margin:100px auto;"> |
|||
<el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm"> |
|||
<el-form-item label="体现账号" prop="age"> |
|||
<el-input v-model="ruleForm.pass" autocomplete="off"></el-input> |
|||
</el-form-item> |
|||
<el-form-item label="账户姓名" prop="pass"> |
|||
<el-input v-model="ruleForm.pass" autocomplete="off"></el-input> |
|||
</el-form-item> |
|||
|
|||
<el-form-item> |
|||
|
|||
<el-button type="primary" @click="submitForm('ruleForm')">提交</el-button> |
|||
<el-button @click="resetForm('ruleForm')">重置</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</div> |
|||
</el-tab-pane> |
|||
</el-tabs> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
export default { |
|||
data() { |
|||
var checkAge = (rule, value, callback) => { |
|||
if (!value) { |
|||
return callback(new Error('年龄不能为空')); |
|||
} |
|||
setTimeout(() => { |
|||
if (!Number.isInteger(value)) { |
|||
callback(new Error('请输入数字值')); |
|||
} else { |
|||
if (value < 18) { |
|||
callback(new Error('必须年满18岁')); |
|||
} else { |
|||
callback(); |
|||
} |
|||
} |
|||
}, 1000); |
|||
}; |
|||
var validatePass = (rule, value, callback) => { |
|||
if (value === '') { |
|||
callback(new Error('请输入密码')); |
|||
} else { |
|||
if (this.ruleForm.checkPass !== '') { |
|||
this.$refs.ruleForm.validateField('checkPass'); |
|||
} |
|||
callback(); |
|||
} |
|||
}; |
|||
var validatePass2 = (rule, value, callback) => { |
|||
if (value === '') { |
|||
callback(new Error('请再次输入密码')); |
|||
} else if (value !== this.ruleForm.pass) { |
|||
callback(new Error('两次输入密码不一致!')); |
|||
} else { |
|||
callback(); |
|||
} |
|||
}; |
|||
return { |
|||
ruleForm: { |
|||
pass: '', |
|||
checkPass: '', |
|||
age: '' |
|||
}, |
|||
rules: { |
|||
pass: [ |
|||
{ validator: validatePass, trigger: 'blur' } |
|||
], |
|||
checkPass: [ |
|||
{ validator: validatePass2, trigger: 'blur' } |
|||
], |
|||
age: [ |
|||
{ validator: checkAge, trigger: 'blur' } |
|||
] |
|||
} |
|||
}; |
|||
}, |
|||
methods: { |
|||
submitForm(formName) { |
|||
this.$refs[formName].validate((valid) => { |
|||
if (valid) { |
|||
alert('submit!'); |
|||
} else { |
|||
console.log('error submit!!'); |
|||
return false; |
|||
} |
|||
}); |
|||
}, |
|||
resetForm(formName) { |
|||
this.$refs[formName].resetFields(); |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
::v-deep .el-tabs__nav-scroll{ |
|||
width: 50%!important; |
|||
margin: 0 auto!important; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,490 @@ |
|||
<template> |
|||
<div> |
|||
<el-tabs tab-position="top" style="" stretch background-color="#545c64"> |
|||
<el-tab-pane label="任务首页"> |
|||
<div style="width:100%;padding: 20px;"> |
|||
<el-row :gutter="20"> |
|||
<el-col :span="16"> |
|||
<div style=""> |
|||
<el-row class="xia" :gutter="20"> |
|||
<el-col :span="6" v-for="(iteam,index) in img1List" :key="index"> |
|||
<el-card :body-style="{ padding: '0px' }"> |
|||
<img src="https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png" class="image"> |
|||
<div style="padding: 14px;"> |
|||
<span>好吃的汉堡</span> |
|||
<div class="bottom clearfix"> |
|||
<time class="time">1.222</time> |
|||
</div> |
|||
</div> |
|||
</el-card> |
|||
</el-col> |
|||
</el-row> |
|||
<el-row class="xia" :gutter="20"> |
|||
<el-col :span="6" v-for="(iteam,index) in img2List" :key="index"> |
|||
<el-card :body-style="{ padding: '0px' }"> |
|||
<img src="https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png" class="image"> |
|||
<div style="padding: 14px;"> |
|||
<span>好吃的汉堡</span> |
|||
<div class="bottom clearfix"> |
|||
<time class="time">1.222</time> |
|||
</div> |
|||
</div> |
|||
</el-card> |
|||
</el-col> |
|||
</el-row> |
|||
<el-row :gutter="20"> |
|||
<el-col :span="16"> |
|||
<el-button type="primary" round>境内推荐</el-button> |
|||
<el-button type="primary" round>欧美日新</el-button> |
|||
<el-button type="primary" round>泰国越柬</el-button> |
|||
<el-button type="primary" round>中东非洲</el-button> |
|||
</el-col> |
|||
<el-col :span="8"> |
|||
<!-- <div>本次收益:100元</div> --> |
|||
</el-col> |
|||
</el-row> |
|||
<!-- <div style="width:70%"> |
|||
<el-row> |
|||
<el-col :span="6"> |
|||
<el-button type="primary" round>主要按钮</el-button> |
|||
</el-col> |
|||
<el-col :span="6"> |
|||
<el-button type="primary" round>主要按钮</el-button> |
|||
</el-col> |
|||
<el-col :span="6"> |
|||
<el-button type="primary" round>主要按钮</el-button> |
|||
</el-col> |
|||
<el-col :span="6"> |
|||
<el-button type="primary" round>主要按钮</el-button> |
|||
</el-col> |
|||
|
|||
|
|||
|
|||
</div> --> |
|||
</div> |
|||
</el-col> |
|||
<el-col :span="8"> |
|||
<div style=""> |
|||
<el-row :gutter="20" class="xia"> |
|||
<el-col :span="8"> |
|||
<el-card class="box-card"> |
|||
可用余额:5元 |
|||
</el-card> |
|||
</el-col> |
|||
<el-col :span="8"> |
|||
<el-card class="box-card"> |
|||
总收益:8元 |
|||
</el-card> |
|||
</el-col> |
|||
<el-col :span="8"> |
|||
<el-card class="box-card"> |
|||
本次收益:2元 |
|||
</el-card> |
|||
|
|||
</el-col> |
|||
|
|||
</el-row> |
|||
<el-row class="xia"> |
|||
<el-card class="box-card"> |
|||
<div slot="header" class="clearfix"> |
|||
<span>任务类型</span> |
|||
<el-button style="float: right; padding: 3px 0" type="text">全选</el-button> |
|||
</div> |
|||
|
|||
<el-row class="xia"> |
|||
<el-col :span="12"> |
|||
<el-checkbox size='medium' v-model="checked1" label="浏览任务" border></el-checkbox> |
|||
</el-col> |
|||
<el-col :span="12"> |
|||
<el-checkbox size='medium' v-model="checked2" label="店铺收藏" border></el-checkbox> |
|||
</el-col> |
|||
</el-row> |
|||
<el-row class="xia"> |
|||
<el-col :span="12"> |
|||
<el-checkbox v-model="checked1" label="实时点赞" border></el-checkbox> |
|||
</el-col> |
|||
<el-col :span="12"> |
|||
<el-checkbox v-model="checked2" label="分享任务" border></el-checkbox> |
|||
</el-col> |
|||
</el-row> |
|||
<el-row class="xia"> |
|||
<el-col :span="12"> |
|||
<el-checkbox v-model="checked1" label="上班任务" border></el-checkbox> |
|||
</el-col> |
|||
<el-col :span="12"> |
|||
<el-checkbox v-model="checked2" label="投票排行" border></el-checkbox> |
|||
</el-col> |
|||
</el-row> |
|||
</el-card> |
|||
</el-row> |
|||
<el-row class="xia"> |
|||
<el-card> |
|||
<el-row> |
|||
<el-col :span="12"> |
|||
任务状态: |
|||
<el-tag type="info" v-if="renwuButkai">未运行</el-tag> |
|||
<el-tag type="success" v-if="renwuButguan">运行中</el-tag> |
|||
</el-col> |
|||
<el-col :span="12"> |
|||
<el-button v-if="renwuButkai" type="primary" plain @click="kaishi">开始任务</el-button> |
|||
<el-button v-if="renwuButguan" type="danger" plain @click="guanbi">关闭任务</el-button> |
|||
</el-col> |
|||
</el-row> |
|||
|
|||
</el-card> |
|||
</el-row> |
|||
<el-row class="xia"> |
|||
<div style="height: 275px;box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1)"> |
|||
<el-scrollbar style="height:100%" wrap-style="overflow-x:hidden;"> |
|||
<ul> |
|||
<li v-for="(iteam,index) in dataList" :key="index"> |
|||
{{iteam.cont}} |
|||
</li> |
|||
</ul> |
|||
</el-scrollbar> |
|||
</div> |
|||
|
|||
</el-row> |
|||
</div> |
|||
</el-col> |
|||
</el-row> |
|||
|
|||
|
|||
<div> |
|||
|
|||
</div> |
|||
</div> |
|||
</el-tab-pane> |
|||
<el-tab-pane label="修改密码"> |
|||
<div style="width:18%;margin:100px auto;"> |
|||
<el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm"> |
|||
<el-form-item label="原密码" prop="age"> |
|||
<el-input type="password" v-model.number="ruleForm.age"></el-input> |
|||
</el-form-item> |
|||
<el-form-item label="新密码" prop="pass"> |
|||
<el-input type="password" v-model="ruleForm.pass" autocomplete="off"></el-input> |
|||
</el-form-item> |
|||
<el-form-item label="确认密码" prop="checkPass"> |
|||
<el-input type="password" v-model="ruleForm.checkPass" autocomplete="off"></el-input> |
|||
</el-form-item> |
|||
|
|||
<el-form-item> |
|||
<el-button type="primary" @click="submitForm('ruleForm')">提交</el-button> |
|||
<el-button @click="resetForm('ruleForm')">重置</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</div> |
|||
|
|||
</el-tab-pane> |
|||
<el-tab-pane label="余额提现"> |
|||
<div style="width:18%;margin:100px auto;"> |
|||
<el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm"> |
|||
<el-form-item label="可用余额" prop="age"> |
|||
0.06 |
|||
</el-form-item> |
|||
<el-form-item label="体现金额" prop="pass"> |
|||
<el-input v-model.number="ruleForm.pass" autocomplete="off"></el-input> |
|||
</el-form-item> |
|||
|
|||
<el-form-item> |
|||
|
|||
<el-button type="primary" @click="submitForm('ruleForm')">提交</el-button> |
|||
<el-button @click="resetForm('ruleForm')">重置</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</div> |
|||
</el-tab-pane> |
|||
<el-tab-pane label="账户绑定"> |
|||
<div style="width:18%;margin:100px auto;"> |
|||
<el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm"> |
|||
<el-form-item label="体现账号" prop="age"> |
|||
<el-input v-model="ruleForm.pass" autocomplete="off"></el-input> |
|||
</el-form-item> |
|||
<el-form-item label="账户姓名" prop="pass"> |
|||
<el-input v-model="ruleForm.pass" autocomplete="off"></el-input> |
|||
</el-form-item> |
|||
|
|||
<el-form-item> |
|||
|
|||
<el-button type="primary" @click="submitForm('ruleForm')">提交</el-button> |
|||
<el-button @click="resetForm('ruleForm')">重置</el-button> |
|||
</el-form-item> |
|||
</el-form> |
|||
</div> |
|||
</el-tab-pane> |
|||
</el-tabs> |
|||
<!-- 激活窗口 --> |
|||
<el-dialog |
|||
title="请激活" |
|||
:visible.sync="dialogVisible" |
|||
width="30%"> |
|||
<el-form ref="addForm" :model="jiForm" :rules="rules" label-width="150px"> |
|||
<el-form-item label="激活窗口" prop="share"> |
|||
<el-select v-model="jiForm.window_coord" placeholder="请选择"> |
|||
<el-option label="窗口1" :value=1></el-option> |
|||
<el-option label="窗口2" :value=2></el-option> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="激活码" prop="title"> |
|||
<el-input v-model="jiForm.jihuomaText" autocomplete="off" /> |
|||
</el-form-item> |
|||
</el-form> |
|||
<span slot="footer" class="dialog-footer"> |
|||
<el-button @click="dialogVisible = false">取 消</el-button> |
|||
<el-button type="primary" @click="jihuo">确 定</el-button> |
|||
</span> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { logout,login,register,accountBinding,withdraw,cdkActivation,index,start,checkAndAdd } from '@/api/renwu' |
|||
export default { |
|||
data() { |
|||
var checkAge = (rule, value, callback) => { |
|||
if (!value) { |
|||
return callback(new Error('年龄不能为空')); |
|||
} |
|||
setTimeout(() => { |
|||
if (!Number.isInteger(value)) { |
|||
callback(new Error('请输入数字值')); |
|||
} else { |
|||
if (value < 18) { |
|||
callback(new Error('必须年满18岁')); |
|||
} else { |
|||
callback(); |
|||
} |
|||
} |
|||
}, 1000); |
|||
}; |
|||
var validatePass = (rule, value, callback) => { |
|||
if (value === '') { |
|||
callback(new Error('请输入密码')); |
|||
} else { |
|||
if (this.ruleForm.checkPass !== '') { |
|||
this.$refs.ruleForm.validateField('checkPass'); |
|||
} |
|||
callback(); |
|||
} |
|||
}; |
|||
var validatePass2 = (rule, value, callback) => { |
|||
if (value === '') { |
|||
callback(new Error('请再次输入密码')); |
|||
} else if (value !== this.ruleForm.pass) { |
|||
callback(new Error('两次输入密码不一致!')); |
|||
} else { |
|||
callback(); |
|||
} |
|||
}; |
|||
return { |
|||
// 激活码提交 |
|||
jiForm:{}, |
|||
// 弹框 |
|||
dialogVisible: false, |
|||
// 任务开始按钮 |
|||
renwuButkai:true, |
|||
renwuButguan:false, |
|||
// 滚动条数据 |
|||
dataList:[ |
|||
{ |
|||
tittle:1, |
|||
cont:'可接受的步进电机空手道解放了,,矛盾双方卡号发动漫付款链接哈第三方接口,每次你' |
|||
}, |
|||
{ |
|||
tittle:1, |
|||
cont:'可接受的步进电机空手道解放了,,矛盾双方卡号发动漫付款链接哈第三方接口,每次你' |
|||
}, |
|||
{ |
|||
tittle:1, |
|||
cont:'可接受的步进电机空手道解放了,,矛盾双方卡号发动漫付款链接哈第三方接口,每次你' |
|||
}, |
|||
{ |
|||
tittle:1, |
|||
cont:'可接受的步进电机空手道解放了,,矛盾双方卡号发动漫付款链接哈第三方接口,每次你' |
|||
}, |
|||
{ |
|||
tittle:1, |
|||
cont:'可接受的步进电机空手道解放了,,矛盾双方卡号发动漫付款链接哈第三方接口,每次你' |
|||
}, |
|||
{ |
|||
tittle:1, |
|||
cont:'可接受的步进电机空手道解放了,,矛盾双方卡号发动漫付款链接哈第三方接口,每次你' |
|||
}, |
|||
{ |
|||
tittle:1, |
|||
cont:'可接受的步进电机空手道解放了,,矛盾双方卡号发动漫付款链接哈第三方接口,每次你' |
|||
}, |
|||
{ |
|||
tittle:1, |
|||
cont:'可接受的步进电机空手道解放了,,矛盾双方卡号发动漫付款链接哈第三方接口,每次你' |
|||
}, |
|||
{ |
|||
tittle:1, |
|||
cont:'可接受的步进电机空手道解放了,,矛盾双方卡号发动漫付款链接哈第三方接口,每次你' |
|||
}, |
|||
{ |
|||
tittle:1, |
|||
cont:'可接受的步进电机空手道解放了,,矛盾双方卡号发动漫付款链接哈第三方接口,每次你' |
|||
}, |
|||
{ |
|||
tittle:1, |
|||
cont:'可接受的步进电机空手道解放了,,矛盾双方卡号发动漫付款链接哈第三方接口,每次你' |
|||
}, |
|||
{ |
|||
tittle:1, |
|||
cont:'可接受的步进电机空手道解放了,,矛盾双方卡号发动漫付款链接哈第三方接口,每次你' |
|||
}, |
|||
], |
|||
img1List:[ |
|||
{ |
|||
imgUrl:'https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png' |
|||
}, |
|||
{ |
|||
imgUrl:'https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png' |
|||
}, |
|||
{ |
|||
imgUrl:'https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png' |
|||
}, |
|||
{ |
|||
imgUrl:'https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png' |
|||
}, |
|||
|
|||
], |
|||
img2List:[ |
|||
{ |
|||
imgUrl:'https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png' |
|||
}, |
|||
{ |
|||
imgUrl:'https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png' |
|||
}, |
|||
{ |
|||
imgUrl:'https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png' |
|||
}, |
|||
{ |
|||
imgUrl:'https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png' |
|||
}, |
|||
|
|||
], |
|||
ruleForm: { |
|||
pass: '', |
|||
checkPass: '', |
|||
age: '' |
|||
}, |
|||
timer:0, |
|||
rules: { |
|||
pass: [ |
|||
{ validator: validatePass, trigger: 'blur' } |
|||
], |
|||
checkPass: [ |
|||
{ validator: validatePass2, trigger: 'blur' } |
|||
], |
|||
age: [ |
|||
{ validator: checkAge, trigger: 'blur' } |
|||
] |
|||
} |
|||
}; |
|||
}, |
|||
methods: { |
|||
async jihuo(){ |
|||
const res = await cdkActivation(this.jiForm) |
|||
if (res.code==20011) { |
|||
this.$message({ |
|||
message: '激活成功', |
|||
type: 'success' |
|||
}); |
|||
} |
|||
}, |
|||
// 定时器开始 |
|||
dingshi(){ |
|||
this.timer = setInterval(() => { |
|||
this.dataList.push({ tittle:1,cont:'dfgagadffasdfasdfae' }); |
|||
}, 1000) |
|||
}, |
|||
// 定时器关闭 |
|||
shiguan(){ |
|||
clearInterval(this.timer) |
|||
}, |
|||
// 开始按钮 |
|||
kaishi(){ |
|||
this.renwuButguan=true; |
|||
this.renwuButkai=false; |
|||
this.dingshi() |
|||
}, |
|||
// 关闭按钮 |
|||
guanbi(){ |
|||
this.renwuButguan=false; |
|||
this.renwuButkai=true; |
|||
this.shiguan() |
|||
}, |
|||
submitForm(formName) { |
|||
this.$refs[formName].validate((valid) => { |
|||
if (valid) { |
|||
alert('submit!'); |
|||
} else { |
|||
console.log('error submit!!'); |
|||
return false; |
|||
} |
|||
}); |
|||
}, |
|||
resetForm(formName) { |
|||
this.$refs[formName].resetFields(); |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
::v-deep .el-tabs__nav-scroll{ |
|||
width: 50%!important; |
|||
margin: 0 auto!important; |
|||
} |
|||
.time { |
|||
font-size: 13px; |
|||
color: #999; |
|||
} |
|||
|
|||
.bottom { |
|||
margin-top: 13px; |
|||
line-height: 12px; |
|||
} |
|||
|
|||
.button { |
|||
padding: 0; |
|||
float: right; |
|||
} |
|||
|
|||
.image { |
|||
width: 100%; |
|||
display: block; |
|||
} |
|||
|
|||
.clearfix:before, |
|||
.clearfix:after { |
|||
display: table; |
|||
content: ""; |
|||
} |
|||
|
|||
.clearfix:after { |
|||
clear: both |
|||
} |
|||
.xia{ |
|||
margin-bottom: 20px; |
|||
} |
|||
.el-scrollbar { |
|||
height: 100%; |
|||
} |
|||
.el-scrollbar__wrap { |
|||
overflow: scroll; |
|||
width: 110%; |
|||
height: 120%; |
|||
} |
|||
::-webkit-scrollbar { |
|||
width: 6px; |
|||
height: 6px; |
|||
} |
|||
|
|||
::-webkit-scrollbar-thumb { |
|||
background-color: #eee; |
|||
border-radius: 3px; |
|||
} |
|||
</style> |
|||
@ -0,0 +1,502 @@ |
|||
<template> |
|||
<div class="dashboard-container"> |
|||
<div class="gva-table-box"> |
|||
<div class="gva-btn-list"> |
|||
<el-radio-group v-model="riqi" @change="yueRadio()"> |
|||
<el-radio label=3 border>上两个月</el-radio> |
|||
<el-radio label=2 border>上一个月</el-radio> |
|||
<el-radio label=1 border>当月</el-radio> |
|||
</el-radio-group> |
|||
<!-- <el-radio v-model="riqi" label="1" border>上两个月</el-radio> |
|||
<el-radio v-model="riqi" label="2" border>上一个月</el-radio> |
|||
<el-radio v-model="riqi" label="3" border>当月</el-radio> --> |
|||
<el-button type="primary" @click="processRequest1()" plain >企业微信流程测试</el-button> |
|||
<!-- <el-button size="mini" type="primary" icon="el-icon-plus" @click="openDialog('addApi')">新增</el-button> --> |
|||
</div> |
|||
|
|||
<el-table :data="tableData"> |
|||
<el-table-column align="left" label="考核类型" prop="classTitle"/> |
|||
<el-table-column align="left" label="考核项目" prop="assessTitle"/> |
|||
<el-table-column align="left" label="具体职责" prop="title"/> |
|||
<el-table-column align="left" label="考核部门类型" prop="userType"> |
|||
<template #default="scope"> |
|||
<div v-if="scope.row.userType==1">考核人</div> |
|||
<div v-if="scope.row.userType==2">考核部门</div> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column align="left" label="部门" prop="assessDepart.rescore"> |
|||
<template #default="scope"> |
|||
<div style="margin-bottom: 3px;height: 40px;line-height: 40px;" v-for="(item,i) in scope.row.assessDepart" v-if="item.istrue">{{item.departTitle}}</div> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column align="left" label="基本分" prop="assessDepart.rescore"> |
|||
<template #default="scope"> |
|||
<div style="margin-bottom: 3px;height: 40px;line-height: 40px;" v-for="(item,i) in scope.row.assessDepart" v-if="item.istrue">{{item.rescore}}</div> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column width="210px" align="left" label="加分" > |
|||
<template #default="scope"> |
|||
|
|||
<span v-for="(item,i) in scope.row.assessDepart" v-if="item.istrue"> |
|||
<el-input |
|||
type="number" |
|||
style="margin-bottom: 3px;" |
|||
placeholder="无加分填0!不能大于2" |
|||
v-model="item.extraPoints" |
|||
@input="changeInput" |
|||
clearable> |
|||
</el-input> |
|||
</span> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column width="210px" align="left" label="减分"> |
|||
<template #default="scope"> |
|||
<span v-for="(item,i) in scope.row.assessDepart" v-if="item.istrue"> |
|||
<el-input |
|||
style="margin-bottom: 3px;" |
|||
placeholder="无减分填0!不能大于2" |
|||
v-model="item.deductPoints" |
|||
@input="changeInputJian" |
|||
clearable> |
|||
</el-input> |
|||
</span> |
|||
|
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column align="left" fixed="right" label="操作" width="200"> |
|||
<template #default="scope"> |
|||
<div v-for="(item,i) in scope.row.assessDepart" style="margin-bottom: 3px;height: 40px;line-height: 40px;" v-if="item.istrue"> |
|||
<el-button |
|||
icon="el-icon-edit" |
|||
size="small" |
|||
type="text" |
|||
@click="submit(item,scope.row)" |
|||
>提交</el-button> |
|||
</div> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<!-- <div class="gva-pagination"> |
|||
<el-pagination |
|||
@size-change="handleSizeChange" |
|||
@current-change="handleCurrentChange" |
|||
:page-sizes="[10, 30, 50, 100]" |
|||
:page-size="searchInfo.pageSize" |
|||
layout="total, sizes, prev, pager, next, jumper" |
|||
:total="total"> |
|||
</el-pagination> |
|||
</div> --> |
|||
</div> |
|||
<!-- 打分 --> |
|||
<el-dialog :visible="dialogFormVisible" :before-close="closeDialog" title="打分" width="30%"> |
|||
<el-form ref="apiForm" :model="form" :rules="rules" label-width="150px"> |
|||
<el-form-item label="加分" prop="extraPoints"> |
|||
<el-input v-model="form.extraPoints" placeholder="无加分填0!"/> |
|||
</el-form-item> |
|||
<el-form-item label="减分" prop="deductPoints"> |
|||
<el-input v-model="form.deductPoints" placeholder="无减分填0!"/> |
|||
</el-form-item> |
|||
<el-form-item label="被考核部门" prop="deductPoints"> |
|||
<el-select v-model="form.departId" clearable placeholder="请选择"> |
|||
<el-option |
|||
v-for="item in options" |
|||
:key="item.departId" |
|||
:label="item.departTitle" |
|||
:value="item.departId"> |
|||
</el-option> |
|||
</el-select> |
|||
</el-form-item> |
|||
<el-form-item label="考核日期" prop="fileTime"> |
|||
<el-date-picker |
|||
v-model="form.fileTime" |
|||
type="date" |
|||
placeholder="选择日期" |
|||
value-format="YYYY-MM-DD" |
|||
> |
|||
</el-date-picker> |
|||
<!-- <el-date-picker |
|||
format="YYYY/MM/DD" |
|||
value-format="YYYY-MM-DD" |
|||
v-model="form.fileTime" |
|||
type="date" |
|||
placeholder="选择日期"> |
|||
</el-date-picker> --> |
|||
</el-form-item> |
|||
</el-form> |
|||
<template #footer> |
|||
<div class="dialog-footer"> |
|||
<el-button size="small" @click="closeDialog">取 消</el-button> |
|||
<el-button size="small" type="primary" @click="enterDialog()">提 交</el-button> |
|||
</div> |
|||
</template> |
|||
</el-dialog> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapGetters } from 'vuex' |
|||
import { myassessmentlist,getDutydepartlist,addassessmentscore,getconfig } from '@/api/dutys' |
|||
export default { |
|||
name: 'Dashboard', |
|||
computed: { |
|||
...mapGetters([ |
|||
'name' |
|||
]) |
|||
}, |
|||
data() { |
|||
return { |
|||
hint:'123', |
|||
isCheng:'321', |
|||
processRequestData:{}, |
|||
appProcessRequestFrom:{ |
|||
url:'', |
|||
state:1 |
|||
}, |
|||
processRequestFrom:{ |
|||
url:'http://www.baidu.com', |
|||
state:2 |
|||
}, |
|||
riqi:'3', |
|||
form:{ |
|||
dutyId: "", //具体职责ID |
|||
deductPoints: '', //减分 |
|||
extraPoints: '', //加分 |
|||
score: 0, //实际得分 |
|||
fileTime: "", //考核日期 |
|||
departId: '' //考核部门ID |
|||
}, |
|||
options:{}, |
|||
dialogFormVisible:false, |
|||
total: '', |
|||
tableData:[], |
|||
searchInfo: { |
|||
page: 1, |
|||
pageSize: 10, |
|||
|
|||
}, |
|||
appProcessRequestData:{}, |
|||
rules: { |
|||
parentId: [{ required: true, message: '请选择部门', trigger: 'blur' }], |
|||
score: [{ required: true, message: '请输入分值', trigger: 'blur' }], |
|||
}, |
|||
} |
|||
}, |
|||
created() { |
|||
console.log(this.$store.state.user.token) |
|||
if (this.$store.state.user.token=='') { |
|||
this.$router.push('/login') |
|||
} |
|||
if (this.$store.state.user.token==undefined) { |
|||
this.$router.push('/login') |
|||
} |
|||
this.getMyassessmentlist() |
|||
this.getProcessRequestData() |
|||
}, |
|||
methods: { |
|||
// 监听选择框 |
|||
async yueRadio(){ |
|||
this.searchInfo.daystate=this.riqi |
|||
const res = await myassessmentlist(this.searchInfo) |
|||
}, |
|||
// 发起企业微信流程请求数据 |
|||
async getAppProcessRequestData(){ |
|||
// 当前页面url |
|||
console.log(window.location.href.split("#")[0]) |
|||
this.appProcessRequestFrom.url=window.location.href.split("#")[0]; |
|||
const res = await getconfig(this.appProcessRequestFrom) |
|||
console.log(res) |
|||
this.appProcessRequestData=res.data; |
|||
// this.processRequestData=res.data; |
|||
}, |
|||
// 发起企业微信流程请求数据 |
|||
async getProcessRequestData(){ |
|||
// 当前页面url |
|||
// this.processRequestFrom.url=window.location.href |
|||
const res = await getconfig(this.processRequestFrom) |
|||
this.processRequestData=res.data; |
|||
// this.appProcessRequestData=res.data; |
|||
}, |
|||
async processRequest1(){ |
|||
this.appProcessRequestFrom.url=window.location.href.split("#")[0]; |
|||
|
|||
const respon = await getconfig(this.appProcessRequestFrom) |
|||
if (respon.code==0) { |
|||
console.log("1") |
|||
wx.agentConfig({ |
|||
corpid: respon.data.corpid, // 必填,企业微信的corpid,必须与当前登录的企业一致 |
|||
agentid: respon.data.agentid, // 必填,企业微信的应用id (e.g. 1000247) |
|||
timestamp: respon.data.timestamp, // 必填,生成签名的时间戳 |
|||
nonceStr: respon.data.nonceStr, // 必填,生成签名的随机串 |
|||
signature: respon.data.signature,// 必填,签名,见附录-JS-SDK使用权限签名算法 |
|||
jsApiList: ['selectExternalContact','thirdPartyOpenPage'], //必填,传入需要使用的接口名称 |
|||
success: function(res) { |
|||
// 回调 |
|||
alert('chenggong') |
|||
console.log("chenggong") |
|||
this.isCheng=2 |
|||
wx.invoke('thirdPartyOpenPage', { |
|||
"oaType": "10001",// String |
|||
"templateId": "0ecb2de95a6e186478e4ddc811fd5d86_1812068285",// String |
|||
"thirdNo": respon.data.orderid,// String |
|||
"extData": { |
|||
'fieldList': [{ |
|||
'title': '考核内容', |
|||
'type': 'text', |
|||
'value': '企管部 2022-01 职能考核', |
|||
}, |
|||
{ |
|||
'title': '考核详情', |
|||
'type': 'link', |
|||
'value': 'http://new.hxgk.group/#/details/details?departId=1&time=2021-12', |
|||
}], |
|||
} |
|||
}, |
|||
function(res) { |
|||
// 输出接口的回调信息 |
|||
var str = JSON.stringify(res); |
|||
alert(str) |
|||
}); |
|||
}, |
|||
fail: function(res) { |
|||
alert("失败") |
|||
alert(res.hint) |
|||
console.log("失败") |
|||
this.isCheng=1 |
|||
this.hint=res.hint |
|||
console.log(res) |
|||
if(res.errMsg.indexOf('function not exist') > -1){ |
|||
alert('版本过低请升级') |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
|
|||
}, |
|||
processRequest(){ |
|||
let that = this; |
|||
this.getProcessRequestData(); |
|||
this.getAppProcessRequestData(); |
|||
wx.config({ |
|||
beta: true, |
|||
debug: true, |
|||
appId: this.processRequestData.corpid, |
|||
timestamp: this.processRequestData.timestamp, |
|||
nonceStr: this.processRequestData.nonceStr, |
|||
signature: this.processRequestData.signature, |
|||
jsApiList: ['agentConfig','openUserProfile','thirdPartyOpenPage','selectExternalContact'] |
|||
}); |
|||
console.log(that.processRequestData) |
|||
wx.ready(function (datakkk) { |
|||
|
|||
console.log("ready") |
|||
|
|||
wx.agentConfig({ |
|||
debug:1, |
|||
corpid: that.appProcessRequestData.corpid, |
|||
agentid: that.appProcessRequestData.agentid, |
|||
timestamp: that.appProcessRequestData.timestamp, |
|||
nonceStr: that.appProcessRequestData.nonceStr, |
|||
signature: that.appProcessRequestData.signature, |
|||
jsApiList: ['selectExternalContact'], |
|||
success: function(res) { |
|||
//审批流程js调用 |
|||
alert("agentConfig"); |
|||
wx.invoke('thirdPartyOpenPage', { |
|||
"oaType": "10001", |
|||
"templateId": "0ecb2de95a6e186478e4ddc811fd5d86_1812068285", |
|||
"thirdNo": that.appProcessRequestData.orderid, |
|||
"extData": { |
|||
'fieldList': [{ |
|||
'title': '采购类型', |
|||
'type': 'text', |
|||
'value': '市场活动', |
|||
}, |
|||
{ |
|||
'title': '订单链接', |
|||
'type': 'link', |
|||
'value': 'https://work.weixin.qq.com', |
|||
}], |
|||
} |
|||
}, |
|||
function(res) { |
|||
// 输出接口的回调信息 |
|||
console.log("thirdPartyOpenPage输出接口的回调信息") |
|||
console.log(res) |
|||
alert("thirdPartyOpenPage"); |
|||
alert(res); |
|||
} |
|||
); |
|||
}, |
|||
fail: function(res) { |
|||
console.log("approval提交不通过") |
|||
console.log(res) |
|||
alert("approval提交不通过"); |
|||
alert("agentConfig:"+res.errMsg); |
|||
if(res.errMsg.indexOf('function not exist') > -1){ |
|||
alert('版本过低请升级') |
|||
} |
|||
} |
|||
}); |
|||
|
|||
|
|||
|
|||
}); |
|||
}, |
|||
// 减分 |
|||
changeInputJian(val){ |
|||
this.form.deductPoints=val |
|||
}, |
|||
// 加分 |
|||
changeInput(val){ |
|||
console.log("input") |
|||
console.log(val) |
|||
this.form.extraPoints=val |
|||
}, |
|||
// 循环 |
|||
change: function(e,index) { |
|||
console.log(e.target.value);//实时获取输入值 |
|||
console.log(index);//获取点击输入框的索引 |
|||
}, |
|||
// 提交分数操作 |
|||
async submit(iteam,val){ |
|||
console.log("iteam") |
|||
console.log(iteam) |
|||
console.log("val") |
|||
console.log(val) |
|||
this.form.dutyId=val.outId |
|||
this.form.deductPoints=parseInt(this.form.deductPoints)*10 |
|||
this.form.extraPoints=parseInt(this.form.extraPoints)*10 |
|||
this.form.departId=iteam.departId; |
|||
if (this.riqi=="1") { |
|||
this.getLastTwoMonth() |
|||
} |
|||
if (this.riqi=="2") { |
|||
this.getLastMonth() |
|||
} |
|||
if (this.riqi=="3") { |
|||
this.getNowMonth() |
|||
} |
|||
console.log("this.form.fileTime") |
|||
console.log(this.form.fileTime) |
|||
const res = await addassessmentscore(this.form) |
|||
// if (res==) { |
|||
|
|||
// } |
|||
}, |
|||
// 获取当前月份 |
|||
getNowMonth() { |
|||
var date = new Date(); |
|||
var year = date.getFullYear(); //当前年:四位数字 |
|||
var month = date.getMonth(); //当前月:0-11 |
|||
month=month + 1; |
|||
|
|||
month = month < 10 ? ('0' + month) : month; //月份格式化:月份小于10则追加个0 |
|||
|
|||
this.form.fileTime = year + '-' + month; |
|||
}, |
|||
// 获取上一个月 |
|||
getLastMonth() { |
|||
var date = new Date(); |
|||
var year = date.getFullYear(); //当前年:四位数字 |
|||
var month = date.getMonth(); //当前月:0-11 |
|||
|
|||
if (month == 0) { //如果是0,则说明是1月份,上一个月就是去年的12月 |
|||
year -= 1; |
|||
month = 12; |
|||
} |
|||
|
|||
month = month < 10 ? ('0' + month) : month; //月份格式化:月份小于10则追加个0 |
|||
|
|||
this.form.fileTime = year + '-' + month; |
|||
}, |
|||
// 获取上两个月 |
|||
getLastTwoMonth() { |
|||
var date = new Date(); |
|||
var year = date.getFullYear(); //当前年:四位数字 |
|||
var month = date.getMonth(); //当前月:0-11 |
|||
|
|||
if (month == 0) { //如果是0,则说明是1月份,上一个月就是去年的12月 |
|||
year -= 1; |
|||
month = 11; |
|||
} |
|||
if (month == 1) { //如果是1,则说明是2月份,上一个月就是去年的12月 |
|||
year -= 1; |
|||
month = 12; |
|||
} |
|||
|
|||
month = month < 10 ? ('0' + month) : month; //月份格式化:月份小于10则追加个0 |
|||
|
|||
this.form.fileTime = year + '-' + month; |
|||
}, |
|||
// 提交按钮 |
|||
async enterDialog(){ |
|||
this.form.deductPoints=parseInt(this.form.deductPoints); |
|||
this.form.extraPoints=parseInt(this.form.extraPoints); |
|||
this.form.departId=parseInt(this.form.departId); |
|||
const res = await addassessmentscore(this.form) |
|||
console.log(res) |
|||
|
|||
}, |
|||
initForm() { |
|||
this.$refs.apiForm.resetFields() |
|||
this.form = { |
|||
|
|||
} |
|||
}, |
|||
closeDialog() { |
|||
this.initForm() |
|||
this.dialogFormVisible = false |
|||
}, |
|||
async scoreShow(row) { |
|||
console.log(row) |
|||
const idFrom={ |
|||
id:'', |
|||
} |
|||
idFrom.id=row.outId; |
|||
this.form.dutyId=row.outId; |
|||
console.log("idFrom") |
|||
console.log(idFrom) |
|||
const res = await getDutydepartlist(idFrom) |
|||
this.options=res.data.list; |
|||
this.dialogFormVisible = true |
|||
console.log(this.dialogFormVisible) |
|||
}, |
|||
// 改变pageSize |
|||
handleSizeChange(val) { |
|||
this.searchInfo.pageSize=val |
|||
this.getMyassessmentlist() |
|||
}, |
|||
// 改变page |
|||
handleCurrentChange(val) { |
|||
this.searchInfo.page=val |
|||
this.getMyassessmentlist() |
|||
}, |
|||
async getMyassessmentlist() { |
|||
const res = await myassessmentlist(this.searchInfo) |
|||
this.tableData = res.data.list |
|||
// this.total = res.data.total |
|||
// this.searchInfo.pageSize = res.data.pageSize |
|||
// this.searchInfo.page = res.data.page |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
::v-deep input::-webkit-outer-spin-button, |
|||
::v-deep input::-webkit-inner-spin-button { |
|||
-webkit-appearance: none !important; |
|||
} |
|||
::v-deep input[type='number'] { |
|||
-moz-appearance: textfield !important; |
|||
} |
|||
.dashboard { |
|||
&-container { |
|||
margin: 30px; |
|||
} |
|||
&-text { |
|||
font-size: 30px; |
|||
line-height: 46px; |
|||
} |
|||
} |
|||
</style> |
|||
@ -0,0 +1,87 @@ |
|||
<template> |
|||
<div class="dashboard-container"> |
|||
<div class="gva-table-box"> |
|||
<div class="gva-btn-list"> |
|||
<el-button size="mini" type="primary" icon="el-icon-plus" @click="openDialog('addApi')">新增</el-button> |
|||
</div> |
|||
<el-table :data="tableData"> |
|||
<el-table-column align="left" label="考核类型" prop="classTitle"/> |
|||
<el-table-column align="left" label="考核项目" prop="assessTitle"/> |
|||
<el-table-column align="left" label="具体职责" prop="title"/> |
|||
<el-table-column align="left" label="考核部门类型" prop="userType"> |
|||
<template #default="scope"> |
|||
<div v-if="scope.row.userType==1">考核人</div> |
|||
<div v-if="scope.row.userType==2">考核部门</div> |
|||
</template> |
|||
</el-table-column> |
|||
<el-table-column align="left" label="分值" prop="assessDepart.rescore"/> |
|||
<el-table-column align="left" fixed="right" label="操作" width="200"> |
|||
<template #default="scope"> |
|||
<el-button |
|||
icon="el-icon-edit" |
|||
size="small" |
|||
type="text" |
|||
@click="editApi(scope.row)" |
|||
>编辑</el-button> |
|||
<el-button |
|||
icon="el-icon-delete" |
|||
size="small" |
|||
type="text" |
|||
@click="deleteOperate(scope.row)" |
|||
>删除</el-button> |
|||
</template> |
|||
</el-table-column> |
|||
</el-table> |
|||
<div class="gva-pagination"> |
|||
<el-pagination |
|||
:current-page="page" |
|||
:page-size="pageSize" |
|||
:page-sizes="[10, 30, 50, 100]" |
|||
:total="total" |
|||
layout="total, sizes, prev, pager, next, jumper" |
|||
@current-change="handleCurrentChange" |
|||
@size-change="handleSizeChange" |
|||
/> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</template> |
|||
|
|||
<script> |
|||
import { mapGetters } from 'vuex' |
|||
import { myassessmentlist } from '@/api/dutys' |
|||
export default { |
|||
name: 'Dashboard', |
|||
computed: { |
|||
...mapGetters([ |
|||
'name' |
|||
]) |
|||
}, |
|||
data() { |
|||
return { |
|||
|
|||
} |
|||
}, |
|||
created() { |
|||
// this.getMyassessmentlist() |
|||
}, |
|||
methods: { |
|||
async getMyassessmentlist() { |
|||
const res = await myassessmentlist() |
|||
this.tableData = res.data.list |
|||
} |
|||
} |
|||
} |
|||
</script> |
|||
|
|||
<style lang="scss" scoped> |
|||
.dashboard { |
|||
&-container { |
|||
margin: 30px; |
|||
} |
|||
&-text { |
|||
font-size: 30px; |
|||
line-height: 46px; |
|||
} |
|||
} |
|||
</style> |
|||