init commit & 混料程序模块
							
								
								
									
										2
									
								
								.env.development
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,2 @@
 | 
			
		||||
NODE_ENV=development
 | 
			
		||||
VUE_APP_NODE_ENV=dev
 | 
			
		||||
							
								
								
									
										2
									
								
								.env.production
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,2 @@
 | 
			
		||||
NODE_ENV=production
 | 
			
		||||
VUE_APP_NODE_ENV=prod
 | 
			
		||||
							
								
								
									
										2
									
								
								.env.production.sit
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,2 @@
 | 
			
		||||
NODE_ENV=production
 | 
			
		||||
VUE_APP_NODE_ENV=prod:sit
 | 
			
		||||
							
								
								
									
										2
									
								
								.env.production.uat
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,2 @@
 | 
			
		||||
NODE_ENV=production
 | 
			
		||||
VUE_APP_NODE_ENV=prod:uat
 | 
			
		||||
							
								
								
									
										24
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,24 @@
 | 
			
		||||
.DS_Store
 | 
			
		||||
node_modules
 | 
			
		||||
/dist
 | 
			
		||||
 | 
			
		||||
# local env files
 | 
			
		||||
.env.local
 | 
			
		||||
.env.*.local
 | 
			
		||||
 | 
			
		||||
# Log files
 | 
			
		||||
npm-debug.log*
 | 
			
		||||
yarn-debug.log*
 | 
			
		||||
yarn-error.log*
 | 
			
		||||
 | 
			
		||||
# Editor directories and files
 | 
			
		||||
.idea
 | 
			
		||||
.vscode
 | 
			
		||||
*.suo
 | 
			
		||||
*.ntvs*
 | 
			
		||||
*.njsproj
 | 
			
		||||
*.sln
 | 
			
		||||
*.sw*
 | 
			
		||||
 | 
			
		||||
# lock
 | 
			
		||||
package-lock.json
 | 
			
		||||
							
								
								
									
										201
									
								
								LICENSE
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,201 @@
 | 
			
		||||
                                 Apache License
 | 
			
		||||
                           Version 2.0, January 2004
 | 
			
		||||
                        http://www.apache.org/licenses/
 | 
			
		||||
 | 
			
		||||
   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 | 
			
		||||
 | 
			
		||||
   1. Definitions.
 | 
			
		||||
 | 
			
		||||
      "License" shall mean the terms and conditions for use, reproduction,
 | 
			
		||||
      and distribution as defined by Sections 1 through 9 of this document.
 | 
			
		||||
 | 
			
		||||
      "Licensor" shall mean the copyright owner or entity authorized by
 | 
			
		||||
      the copyright owner that is granting the License.
 | 
			
		||||
 | 
			
		||||
      "Legal Entity" shall mean the union of the acting entity and all
 | 
			
		||||
      other entities that control, are controlled by, or are under common
 | 
			
		||||
      control with that entity. For the purposes of this definition,
 | 
			
		||||
      "control" means (i) the power, direct or indirect, to cause the
 | 
			
		||||
      direction or management of such entity, whether by contract or
 | 
			
		||||
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
 | 
			
		||||
      outstanding shares, or (iii) beneficial ownership of such entity.
 | 
			
		||||
 | 
			
		||||
      "You" (or "Your") shall mean an individual or Legal Entity
 | 
			
		||||
      exercising permissions granted by this License.
 | 
			
		||||
 | 
			
		||||
      "Source" form shall mean the preferred form for making modifications,
 | 
			
		||||
      including but not limited to software source code, documentation
 | 
			
		||||
      source, and configuration files.
 | 
			
		||||
 | 
			
		||||
      "Object" form shall mean any form resulting from mechanical
 | 
			
		||||
      transformation or translation of a Source form, including but
 | 
			
		||||
      not limited to compiled object code, generated documentation,
 | 
			
		||||
      and conversions to other media types.
 | 
			
		||||
 | 
			
		||||
      "Work" shall mean the work of authorship, whether in Source or
 | 
			
		||||
      Object form, made available under the License, as indicated by a
 | 
			
		||||
      copyright notice that is included in or attached to the work
 | 
			
		||||
      (an example is provided in the Appendix below).
 | 
			
		||||
 | 
			
		||||
      "Derivative Works" shall mean any work, whether in Source or Object
 | 
			
		||||
      form, that is based on (or derived from) the Work and for which the
 | 
			
		||||
      editorial revisions, annotations, elaborations, or other modifications
 | 
			
		||||
      represent, as a whole, an original work of authorship. For the purposes
 | 
			
		||||
      of this License, Derivative Works shall not include works that remain
 | 
			
		||||
      separable from, or merely link (or bind by name) to the interfaces of,
 | 
			
		||||
      the Work and Derivative Works thereof.
 | 
			
		||||
 | 
			
		||||
      "Contribution" shall mean any work of authorship, including
 | 
			
		||||
      the original version of the Work and any modifications or additions
 | 
			
		||||
      to that Work or Derivative Works thereof, that is intentionally
 | 
			
		||||
      submitted to Licensor for inclusion in the Work by the copyright owner
 | 
			
		||||
      or by an individual or Legal Entity authorized to submit on behalf of
 | 
			
		||||
      the copyright owner. For the purposes of this definition, "submitted"
 | 
			
		||||
      means any form of electronic, verbal, or written communication sent
 | 
			
		||||
      to the Licensor or its representatives, including but not limited to
 | 
			
		||||
      communication on electronic mailing lists, source code control systems,
 | 
			
		||||
      and issue tracking systems that are managed by, or on behalf of, the
 | 
			
		||||
      Licensor for the purpose of discussing and improving the Work, but
 | 
			
		||||
      excluding communication that is conspicuously marked or otherwise
 | 
			
		||||
      designated in writing by the copyright owner as "Not a Contribution."
 | 
			
		||||
 | 
			
		||||
      "Contributor" shall mean Licensor and any individual or Legal Entity
 | 
			
		||||
      on behalf of whom a Contribution has been received by Licensor and
 | 
			
		||||
      subsequently incorporated within the Work.
 | 
			
		||||
 | 
			
		||||
   2. Grant of Copyright License. Subject to the terms and conditions of
 | 
			
		||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
			
		||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
			
		||||
      copyright license to reproduce, prepare Derivative Works of,
 | 
			
		||||
      publicly display, publicly perform, sublicense, and distribute the
 | 
			
		||||
      Work and such Derivative Works in Source or Object form.
 | 
			
		||||
 | 
			
		||||
   3. Grant of Patent License. Subject to the terms and conditions of
 | 
			
		||||
      this License, each Contributor hereby grants to You a perpetual,
 | 
			
		||||
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 | 
			
		||||
      (except as stated in this section) patent license to make, have made,
 | 
			
		||||
      use, offer to sell, sell, import, and otherwise transfer the Work,
 | 
			
		||||
      where such license applies only to those patent claims licensable
 | 
			
		||||
      by such Contributor that are necessarily infringed by their
 | 
			
		||||
      Contribution(s) alone or by combination of their Contribution(s)
 | 
			
		||||
      with the Work to which such Contribution(s) was submitted. If You
 | 
			
		||||
      institute patent litigation against any entity (including a
 | 
			
		||||
      cross-claim or counterclaim in a lawsuit) alleging that the Work
 | 
			
		||||
      or a Contribution incorporated within the Work constitutes direct
 | 
			
		||||
      or contributory patent infringement, then any patent licenses
 | 
			
		||||
      granted to You under this License for that Work shall terminate
 | 
			
		||||
      as of the date such litigation is filed.
 | 
			
		||||
 | 
			
		||||
   4. Redistribution. You may reproduce and distribute copies of the
 | 
			
		||||
      Work or Derivative Works thereof in any medium, with or without
 | 
			
		||||
      modifications, and in Source or Object form, provided that You
 | 
			
		||||
      meet the following conditions:
 | 
			
		||||
 | 
			
		||||
      (a) You must give any other recipients of the Work or
 | 
			
		||||
          Derivative Works a copy of this License; and
 | 
			
		||||
 | 
			
		||||
      (b) You must cause any modified files to carry prominent notices
 | 
			
		||||
          stating that You changed the files; and
 | 
			
		||||
 | 
			
		||||
      (c) You must retain, in the Source form of any Derivative Works
 | 
			
		||||
          that You distribute, all copyright, patent, trademark, and
 | 
			
		||||
          attribution notices from the Source form of the Work,
 | 
			
		||||
          excluding those notices that do not pertain to any part of
 | 
			
		||||
          the Derivative Works; and
 | 
			
		||||
 | 
			
		||||
      (d) If the Work includes a "NOTICE" text file as part of its
 | 
			
		||||
          distribution, then any Derivative Works that You distribute must
 | 
			
		||||
          include a readable copy of the attribution notices contained
 | 
			
		||||
          within such NOTICE file, excluding those notices that do not
 | 
			
		||||
          pertain to any part of the Derivative Works, in at least one
 | 
			
		||||
          of the following places: within a NOTICE text file distributed
 | 
			
		||||
          as part of the Derivative Works; within the Source form or
 | 
			
		||||
          documentation, if provided along with the Derivative Works; or,
 | 
			
		||||
          within a display generated by the Derivative Works, if and
 | 
			
		||||
          wherever such third-party notices normally appear. The contents
 | 
			
		||||
          of the NOTICE file are for informational purposes only and
 | 
			
		||||
          do not modify the License. You may add Your own attribution
 | 
			
		||||
          notices within Derivative Works that You distribute, alongside
 | 
			
		||||
          or as an addendum to the NOTICE text from the Work, provided
 | 
			
		||||
          that such additional attribution notices cannot be construed
 | 
			
		||||
          as modifying the License.
 | 
			
		||||
 | 
			
		||||
      You may add Your own copyright statement to Your modifications and
 | 
			
		||||
      may provide additional or different license terms and conditions
 | 
			
		||||
      for use, reproduction, or distribution of Your modifications, or
 | 
			
		||||
      for any such Derivative Works as a whole, provided Your use,
 | 
			
		||||
      reproduction, and distribution of the Work otherwise complies with
 | 
			
		||||
      the conditions stated in this License.
 | 
			
		||||
 | 
			
		||||
   5. Submission of Contributions. Unless You explicitly state otherwise,
 | 
			
		||||
      any Contribution intentionally submitted for inclusion in the Work
 | 
			
		||||
      by You to the Licensor shall be under the terms and conditions of
 | 
			
		||||
      this License, without any additional terms or conditions.
 | 
			
		||||
      Notwithstanding the above, nothing herein shall supersede or modify
 | 
			
		||||
      the terms of any separate license agreement you may have executed
 | 
			
		||||
      with Licensor regarding such Contributions.
 | 
			
		||||
 | 
			
		||||
   6. Trademarks. This License does not grant permission to use the trade
 | 
			
		||||
      names, trademarks, service marks, or product names of the Licensor,
 | 
			
		||||
      except as required for reasonable and customary use in describing the
 | 
			
		||||
      origin of the Work and reproducing the content of the NOTICE file.
 | 
			
		||||
 | 
			
		||||
   7. Disclaimer of Warranty. Unless required by applicable law or
 | 
			
		||||
      agreed to in writing, Licensor provides the Work (and each
 | 
			
		||||
      Contributor provides its Contributions) on an "AS IS" BASIS,
 | 
			
		||||
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 | 
			
		||||
      implied, including, without limitation, any warranties or conditions
 | 
			
		||||
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
 | 
			
		||||
      PARTICULAR PURPOSE. You are solely responsible for determining the
 | 
			
		||||
      appropriateness of using or redistributing the Work and assume any
 | 
			
		||||
      risks associated with Your exercise of permissions under this License.
 | 
			
		||||
 | 
			
		||||
   8. Limitation of Liability. In no event and under no legal theory,
 | 
			
		||||
      whether in tort (including negligence), contract, or otherwise,
 | 
			
		||||
      unless required by applicable law (such as deliberate and grossly
 | 
			
		||||
      negligent acts) or agreed to in writing, shall any Contributor be
 | 
			
		||||
      liable to You for damages, including any direct, indirect, special,
 | 
			
		||||
      incidental, or consequential damages of any character arising as a
 | 
			
		||||
      result of this License or out of the use or inability to use the
 | 
			
		||||
      Work (including but not limited to damages for loss of goodwill,
 | 
			
		||||
      work stoppage, computer failure or malfunction, or any and all
 | 
			
		||||
      other commercial damages or losses), even if such Contributor
 | 
			
		||||
      has been advised of the possibility of such damages.
 | 
			
		||||
 | 
			
		||||
   9. Accepting Warranty or Additional Liability. While redistributing
 | 
			
		||||
      the Work or Derivative Works thereof, You may choose to offer,
 | 
			
		||||
      and charge a fee for, acceptance of support, warranty, indemnity,
 | 
			
		||||
      or other liability obligations and/or rights consistent with this
 | 
			
		||||
      License. However, in accepting such obligations, You may act only
 | 
			
		||||
      on Your own behalf and on Your sole responsibility, not on behalf
 | 
			
		||||
      of any other Contributor, and only if You agree to indemnify,
 | 
			
		||||
      defend, and hold each Contributor harmless for any liability
 | 
			
		||||
      incurred by, or claims asserted against, such Contributor by reason
 | 
			
		||||
      of your accepting any such warranty or additional liability.
 | 
			
		||||
 | 
			
		||||
   END OF TERMS AND CONDITIONS
 | 
			
		||||
 | 
			
		||||
   APPENDIX: How to apply the Apache License to your work.
 | 
			
		||||
 | 
			
		||||
      To apply the Apache License to your work, attach the following
 | 
			
		||||
      boilerplate notice, with the fields enclosed by brackets "[]"
 | 
			
		||||
      replaced with your own identifying information. (Don't include
 | 
			
		||||
      the brackets!)  The text should be enclosed in the appropriate
 | 
			
		||||
      comment syntax for the file format. We also recommend that a
 | 
			
		||||
      file or class name and description of purpose be included on the
 | 
			
		||||
      same "printed page" as the copyright notice for easier
 | 
			
		||||
      identification within third-party archives.
 | 
			
		||||
 | 
			
		||||
   Copyright [yyyy] [name of copyright owner]
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
   You may obtain a copy of the License at
 | 
			
		||||
 | 
			
		||||
       http://www.apache.org/licenses/LICENSE-2.0
 | 
			
		||||
 | 
			
		||||
   Unless required by applicable law or agreed to in writing, software
 | 
			
		||||
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
			
		||||
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
			
		||||
   See the License for the specific language governing permissions and
 | 
			
		||||
   limitations under the License.
 | 
			
		||||
							
								
								
									
										104
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,104 @@
 | 
			
		||||
## renren-ui
 | 
			
		||||
- renren-ui基于vue、element-ui构建开发,实现 【[renren-security](https://gitee.com/renrenio/renren-security)】 后台管理前端功能,提供一套更优的前端解决方案
 | 
			
		||||
- 前后端分离,通过token进行数据交互,可独立部署
 | 
			
		||||
- 动态菜单,通过菜单管理统一管理访问路由
 | 
			
		||||
- 后端地址:https://gitee.com/renrenio/renren-security
 | 
			
		||||
- 演示地址:[http://demo.open.renren.io/renren-security](http://demo.open.renren.io/renren-security) (账号密码:admin/admin)
 | 
			
		||||
 | 
			
		||||
<br> 
 | 
			
		||||
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
## 安装
 | 
			
		||||
 | 
			
		||||
您需要提前在本地安装[Node.js](https://nodejs.org/en/),版本号为:14.x,再使用[Git](https://git-scm.com/)克隆项目或者直接下载项目后,然后通过`终端命令行`执行以下命令。
 | 
			
		||||
 | 
			
		||||
```bash
 | 
			
		||||
# 切换到项目根目录
 | 
			
		||||
 | 
			
		||||
# 安装插件
 | 
			
		||||
npm install
 | 
			
		||||
 | 
			
		||||
# 启动项目
 | 
			
		||||
npm run serve
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
> 如网络不稳定,安装时出错或进度过慢!请移步 [cnpm](https://npmmirror.com/) 淘宝镜像进行安装。
 | 
			
		||||
 | 
			
		||||
启动完成后,会自动打开浏览器访问 [http://localhost:8001](http://localhost:8001),如您看到下面的页面代表`前端项目`运行成功!因为前后端分离项目,需保证`前端项目`和`后台项目`分别独立正常运行。
 | 
			
		||||
 | 
			
		||||
请留意下面的页面,其中`验证码`未能正常显示,控制台有`API请求`报错信息!这时需检查`后台项目`是否正常运行。
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## 技术栈
 | 
			
		||||
 | 
			
		||||
提前了解和学习这些知识会对使用本项目有很大的帮助。
 | 
			
		||||
 | 
			
		||||
* [Node.js](https://nodejs.org/)
 | 
			
		||||
* [ES6](http://es6.ruanyifeng.com/)
 | 
			
		||||
* [Vue-cli](https://github.com/vuejs/vue-cli)
 | 
			
		||||
* [Vue](https://cn.vuejs.org/)
 | 
			
		||||
* [Vue-router](https://router.vuejs.org/zh/)
 | 
			
		||||
* [Vuex](https://vuex.vuejs.org/zh/)
 | 
			
		||||
* [Vue-i18n](https://github.com/kazupon/vue-i18n)
 | 
			
		||||
* [Axios](https://github.com/axios/axios)
 | 
			
		||||
* [Element](https://element.eleme.cn/#/zh-CN)
 | 
			
		||||
* [JS-cookie](https://github.com/js-cookie/js-cookie)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
## 目录结构
 | 
			
		||||
 | 
			
		||||
```
 | 
			
		||||
├── src                        
 | 
			
		||||
│  ├── assets                 // 静态资源
 | 
			
		||||
│  ├── components             // 公共组件
 | 
			
		||||
│  ├── element-ui             // element样式
 | 
			
		||||
│  ├── i18n                   // 国际化
 | 
			
		||||
│  ├── icons                  // 图标
 | 
			
		||||
│  ├── mixins                 // 混入
 | 
			
		||||
│  ├── router                 // 路由
 | 
			
		||||
│  ├── store                  // 状态管理
 | 
			
		||||
│  ├── utils                  // 工具类
 | 
			
		||||
│  ├── views                  // 业务相关
 | 
			
		||||
│  ├── App.vue
 | 
			
		||||
│  ├── main.js                // 入口
 | 
			
		||||
├── ...
 | 
			
		||||
├── package-lock.json
 | 
			
		||||
├── package.json
 | 
			
		||||
└── vue.config.js             // vue-cli脚手架配置
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
<br>
 | 
			
		||||
 | 
			
		||||
## 常见问题
 | 
			
		||||
 | 
			
		||||
如何修改API请求地址?
 | 
			
		||||
* 修改`/src/pubilc/index.html`文件中`<!-- 开发环境 -->`注释下的`window.SITE_CONFIG['apiURL']`变量值。
 | 
			
		||||
```
 | 
			
		||||
<!-- 开发环境 -->
 | 
			
		||||
<% if (process.env.VUE_APP_NODE_ENV === 'dev') { %>
 | 
			
		||||
<script>
 | 
			
		||||
window.SITE_CONFIG['apiURL'] = 'http://localhost:8080/renren-admin';
 | 
			
		||||
</script>
 | 
			
		||||
<% } %>
 | 
			
		||||
```
 | 
			
		||||
<br>
 | 
			
		||||
 | 
			
		||||
## 如何交流、反馈、参与贡献?
 | 
			
		||||
- 开发文档:https://www.renren.io/guide/security
 | 
			
		||||
- 官方社区:https://www.renren.io/community
 | 
			
		||||
- Gitee仓库:https://gitee.com/renrenio/renren-ui
 | 
			
		||||
- [人人开源](https://www.renren.io):https://www.renren.io
 | 
			
		||||
- 如需关注项目最新动态,请Watch、Star项目,同时也是对项目最好的支持
 | 
			
		||||
- 技术讨论、二次开发等咨询、问题和建议,请移步到官方社区,我会在第一时间进行解答和回复!
 | 
			
		||||
- 微信扫码并关注【人人开源】,获得项目最新动态及更新提醒<br>
 | 
			
		||||
 | 
			
		||||
  <br>
 | 
			
		||||
 | 
			
		||||
## 微信交流群
 | 
			
		||||
我们提供了微信交流群,扫码下面的二维码,关注【人人开源】公众号,回复【加群】,即可根据提示加入微信群!
 | 
			
		||||
<br><br>
 | 
			
		||||

 | 
			
		||||
 | 
			
		||||
<br>
 | 
			
		||||
<br>
 | 
			
		||||
							
								
								
									
										5
									
								
								babel.config.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,5 @@
 | 
			
		||||
module.exports = {
 | 
			
		||||
  presets: [
 | 
			
		||||
    '@vue/cli-plugin-babel/preset'
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										54
									
								
								package.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,54 @@
 | 
			
		||||
{
 | 
			
		||||
  "name": "renren-ui",
 | 
			
		||||
  "version": "5.0.0",
 | 
			
		||||
  "private": true,
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "dev": "vue-cli-service serve",
 | 
			
		||||
    "build": "vue-cli-service build",
 | 
			
		||||
    "build:prod": "vue-cli-service build --mode production",
 | 
			
		||||
    "build:sit": "vue-cli-service build --mode production.sit",
 | 
			
		||||
    "build:uat": "vue-cli-service build --mode production.uat"
 | 
			
		||||
  },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "@antv/x6": "^1.33.1",
 | 
			
		||||
    "@antv/x6-react-components": "^1.1.15",
 | 
			
		||||
    "axios": "^0.19.2",
 | 
			
		||||
    "babel-eslint": "^8.0.1",
 | 
			
		||||
    "babel-plugin-component": "^1.1.1",
 | 
			
		||||
    "code-brick-zj": "^0.0.7",
 | 
			
		||||
    "core-js": "^3.6.5",
 | 
			
		||||
    "echarts": "^5.3.3",
 | 
			
		||||
    "element-theme": "^2.0.1",
 | 
			
		||||
    "element-ui": "^2.15.7",
 | 
			
		||||
    "js-cookie": "^2.2.1",
 | 
			
		||||
    "lodash": "^4.17.19",
 | 
			
		||||
    "moment": "^2.29.4",
 | 
			
		||||
    "qs": "^6.9.4",
 | 
			
		||||
    "quill": "^1.3.7",
 | 
			
		||||
    "sass": "^1.26.5",
 | 
			
		||||
    "sass-loader": "^9.0.2",
 | 
			
		||||
    "screenfull": "^4.2.1",
 | 
			
		||||
    "svg-sprite-loader": "^5.2.1",
 | 
			
		||||
    "vue": "^2.6.11",
 | 
			
		||||
    "vue-cron": "^1.0.9",
 | 
			
		||||
    "vue-i18n": "^8.18.2",
 | 
			
		||||
    "vue-router": "3.0.7",
 | 
			
		||||
    "vuex": "^3.5.1"
 | 
			
		||||
  },
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "@vue/cli-plugin-babel": "^4.4.6",
 | 
			
		||||
    "@vue/cli-service": "^4.4.6",
 | 
			
		||||
    "element-theme-chalk": "^2.15.7",
 | 
			
		||||
    "natives": "^1.1.6",
 | 
			
		||||
    "vue-template-compiler": "^2.6.11"
 | 
			
		||||
  },
 | 
			
		||||
  "browserslist": [
 | 
			
		||||
    "> 1%",
 | 
			
		||||
    "last 2 versions",
 | 
			
		||||
    "not ie <= 10"
 | 
			
		||||
  ],
 | 
			
		||||
  "engines": {
 | 
			
		||||
    "node": ">= 8.11.1",
 | 
			
		||||
    "npm": ">= 5.6.0"
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								public/1.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 293 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								public/favicon.ico
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.9 KiB  | 
							
								
								
									
										65
									
								
								public/index.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,65 @@
 | 
			
		||||
<!--
 | 
			
		||||
 * @Author: zwq
 | 
			
		||||
 * @Date: 2022-08-22 14:57:50
 | 
			
		||||
 * @LastEditors: zwq
 | 
			
		||||
 * @LastEditTime: 2023-01-04 11:27:34
 | 
			
		||||
 * @Description: 
 | 
			
		||||
-->
 | 
			
		||||
<!DOCTYPE html>
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
  <meta charset="UTF-8">
 | 
			
		||||
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
 | 
			
		||||
  <link rel="shortcut icon" href="<%= BASE_URL %>spc.jpg">
 | 
			
		||||
  <!-- 站点配置 -->
 | 
			
		||||
  <script>
 | 
			
		||||
    window.SITE_CONFIG = {};
 | 
			
		||||
    window.SITE_CONFIG['version'] = 'v5.0.0';
 | 
			
		||||
    window.SITE_CONFIG['nodeEnv'] = '<%= process.env.VUE_APP_NODE_ENV %>';
 | 
			
		||||
    window.SITE_CONFIG['apiURL'] = '';                      // api请求地址
 | 
			
		||||
    window.SITE_CONFIG['storeState'] = {};                  // vuex本地储存初始化状态(用于不刷新页面的情况下,也能重置初始化项目中所有状态)
 | 
			
		||||
    window.SITE_CONFIG['contentTabDefault'] = {             // 内容标签页默认属性对象
 | 
			
		||||
      'name': '',        // 名称, 由 this.$route.name 自动赋值(默认,名称 === 路由名称 === 路由路径)
 | 
			
		||||
      'params': {},      // 参数, 由 this.$route.params 自动赋值
 | 
			
		||||
      'query': {},       // 查询参数, 由 this.$route.query 自动赋值
 | 
			
		||||
      'menuId': '',      // 菜单id(用于选中侧边栏菜单,与this.$store.state.sidebarMenuActiveName进行匹配)
 | 
			
		||||
      'title': '',       // 标题
 | 
			
		||||
      'isTab': true,     // 是否通过tab展示内容?
 | 
			
		||||
      'iframeURL': ''    // 是否通过iframe嵌套展示内容? (以http[s]://开头, 自动匹配)
 | 
			
		||||
    };
 | 
			
		||||
    window.SITE_CONFIG['menuList'] = [];                     // 左侧菜单列表(后台返回,未做处理)
 | 
			
		||||
    window.SITE_CONFIG['permissions'] = [];                  // 页面按钮操作权限(后台返回,未做处理)
 | 
			
		||||
    window.SITE_CONFIG['dynamicRoutes'] = [];                // 动态路由列表
 | 
			
		||||
    window.SITE_CONFIG['dynamicMenuRoutes'] = [];            // 动态(菜单)路由列表
 | 
			
		||||
    window.SITE_CONFIG['dynamicMenuRoutesHasAdded'] = false; // 动态(菜单)路由是否已经添加的状态标示(用于判断是否需要重新拉取数据并进行动态添加操作)
 | 
			
		||||
  </script>
 | 
			
		||||
 | 
			
		||||
  <!-- 开发环境 -->
 | 
			
		||||
  <% if (process.env.VUE_APP_NODE_ENV === 'dev') { %>
 | 
			
		||||
    <script>
 | 
			
		||||
    window.SITE_CONFIG['apiURL'] = 'http://192.168.1.103:8080/pms-am';
 | 
			
		||||
    </script>
 | 
			
		||||
  <% } %>
 | 
			
		||||
  <!-- 集成测试环境 -->
 | 
			
		||||
  <% if (process.env.VUE_APP_NODE_ENV === 'prod:sit') { %>
 | 
			
		||||
    <script>
 | 
			
		||||
      window.SITE_CONFIG['apiURL'] = 'http://localhost:8080/renren-admin';
 | 
			
		||||
    </script>
 | 
			
		||||
  <% } %>
 | 
			
		||||
  <!-- 验收测试环境 -->
 | 
			
		||||
  <% if (process.env.VUE_APP_NODE_ENV === 'prod:uat') { %>
 | 
			
		||||
    <script>
 | 
			
		||||
      window.SITE_CONFIG['apiURL'] = 'http://localhost:8080/renren-admin';
 | 
			
		||||
    </script>
 | 
			
		||||
  <% } %>
 | 
			
		||||
  <!-- 生产环境 -->
 | 
			
		||||
  <% if (process.env.VUE_APP_NODE_ENV === 'prod') { %>
 | 
			
		||||
    <script>
 | 
			
		||||
      window.SITE_CONFIG['apiURL'] = 'http://localhost:8080/renren-admin';
 | 
			
		||||
    </script>
 | 
			
		||||
  <% } %>
 | 
			
		||||
</head>
 | 
			
		||||
<body>
 | 
			
		||||
  <div id="app"></div>
 | 
			
		||||
</body>
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								public/spc.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 74 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								public/wechat.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 27 KiB  | 
							
								
								
									
										34
									
								
								src/App.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,34 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <transition name="el-fade-in-linear">
 | 
			
		||||
    <router-view />
 | 
			
		||||
  </transition>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style>
 | 
			
		||||
  .el-table th.gutter{
 | 
			
		||||
    display: table-cell!important;
 | 
			
		||||
  }
 | 
			
		||||
</style>
 | 
			
		||||
<script>
 | 
			
		||||
import Cookies from 'js-cookie'
 | 
			
		||||
import { messages } from '@/i18n'
 | 
			
		||||
export default {
 | 
			
		||||
  watch: {
 | 
			
		||||
    '$i18n.locale': 'i18nHandle'
 | 
			
		||||
  },
 | 
			
		||||
  created () {
 | 
			
		||||
    this.i18nHandle(this.$i18n.locale)
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    i18nHandle (val, oldVal) {
 | 
			
		||||
      Cookies.set('language', val)
 | 
			
		||||
      document.querySelector('html').setAttribute('lang', val)
 | 
			
		||||
      document.title = messages[val].brand.lg
 | 
			
		||||
      // 非登录页面,切换语言刷新页面
 | 
			
		||||
      if (this.$route.name !== 'login' && oldVal) {
 | 
			
		||||
        window.location.reload()
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/avatar.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 90 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/cnbm.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 1.9 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/login-back.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 42 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/login.gif
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 4.6 MiB  | 
							
								
								
									
										
											BIN
										
									
								
								src/assets/img/login_bg.jpg
									
									
									
									
									
										Normal file
									
								
							
							
						
						| 
		 After Width: | Height: | Size: 135 KiB  | 
							
								
								
									
										11
									
								
								src/assets/scss/aui.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,11 @@
 | 
			
		||||
// 变量
 | 
			
		||||
@import "~@/element-ui/theme-variables.scss";
 | 
			
		||||
@import "./variables.scss";
 | 
			
		||||
// 公共
 | 
			
		||||
@import "./normalize.scss";
 | 
			
		||||
@import "./common.scss";
 | 
			
		||||
// 页面
 | 
			
		||||
@import "./pages/login.scss";
 | 
			
		||||
@import "./pages/404.scss";
 | 
			
		||||
// 模块
 | 
			
		||||
@import "./modules/home.scss";
 | 
			
		||||
							
								
								
									
										726
									
								
								src/assets/scss/common.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,726 @@
 | 
			
		||||
*,
 | 
			
		||||
*:before,
 | 
			
		||||
*:after {
 | 
			
		||||
  box-sizing: border-box;
 | 
			
		||||
}
 | 
			
		||||
body {
 | 
			
		||||
  font-family: "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei",
 | 
			
		||||
    "微软雅黑", Arial, sans-serif;
 | 
			
		||||
  font-size: $--font-size-base;
 | 
			
		||||
  line-height: $base--line-height;
 | 
			
		||||
  color: $--color-text-primary;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
}
 | 
			
		||||
a {
 | 
			
		||||
  color: mix(#fff, $--color-primary, 20%);
 | 
			
		||||
  text-decoration: none;
 | 
			
		||||
  &:focus,
 | 
			
		||||
  &:hover {
 | 
			
		||||
    color: $--color-primary;
 | 
			
		||||
    text-decoration: underline;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
img {
 | 
			
		||||
  vertical-align: middle;
 | 
			
		||||
}
 | 
			
		||||
:focus,
 | 
			
		||||
:hover {
 | 
			
		||||
  outline: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Utils
 | 
			
		||||
------------------------------ */
 | 
			
		||||
[v-cloak] {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
.clearfix:before,
 | 
			
		||||
.clearfix:after {
 | 
			
		||||
  content: " ";
 | 
			
		||||
  display: table;
 | 
			
		||||
}
 | 
			
		||||
.clearfix:after {
 | 
			
		||||
  clear: both;
 | 
			
		||||
}
 | 
			
		||||
.fr {
 | 
			
		||||
  float: right !important;
 | 
			
		||||
}
 | 
			
		||||
.fl {
 | 
			
		||||
  float: left !important;
 | 
			
		||||
}
 | 
			
		||||
.fi {
 | 
			
		||||
  float: initial !important;
 | 
			
		||||
}
 | 
			
		||||
.m-auto {
 | 
			
		||||
  margin: auto !important;
 | 
			
		||||
}
 | 
			
		||||
.mt-auto {
 | 
			
		||||
  margin-top: auto !important;
 | 
			
		||||
}
 | 
			
		||||
.mr-auto {
 | 
			
		||||
  margin-right: auto !important;
 | 
			
		||||
}
 | 
			
		||||
.mb-auto {
 | 
			
		||||
  margin-bottom: auto !important;
 | 
			
		||||
}
 | 
			
		||||
.ml-auto {
 | 
			
		||||
  margin-left: auto !important;
 | 
			
		||||
}
 | 
			
		||||
.text-right {
 | 
			
		||||
  text-align: right !important;
 | 
			
		||||
}
 | 
			
		||||
.text-center {
 | 
			
		||||
  text-align: center !important;
 | 
			
		||||
}
 | 
			
		||||
.text-left {
 | 
			
		||||
  text-align: left !important;
 | 
			
		||||
}
 | 
			
		||||
.w-percent-100 {
 | 
			
		||||
  width: 100% !important;
 | 
			
		||||
}
 | 
			
		||||
.base-line-height {
 | 
			
		||||
  line-height: $base--line-height !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Reset element-ui
 | 
			
		||||
------------------------------ */
 | 
			
		||||
.aui-wrapper {
 | 
			
		||||
  .el-card + .el-card {
 | 
			
		||||
    margin-top: 15px;
 | 
			
		||||
  }
 | 
			
		||||
  .el-input__prefix .el-input__icon {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
  }
 | 
			
		||||
  .el-date-editor .el-range-separator {
 | 
			
		||||
    width: 8%;
 | 
			
		||||
  }
 | 
			
		||||
  .el-table th {
 | 
			
		||||
    color: $--color-text-primary;
 | 
			
		||||
    background-color: $--background-color-base;
 | 
			
		||||
  }
 | 
			
		||||
  .el-pagination {
 | 
			
		||||
    margin-top: 15px;
 | 
			
		||||
    text-align: right;
 | 
			
		||||
  }
 | 
			
		||||
  .el-table__expand-icon {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    width: 14px;
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
    margin-right: 5px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Common
 | 
			
		||||
------------------------------ */
 | 
			
		||||
// 图标
 | 
			
		||||
.icon-svg {
 | 
			
		||||
  width: 1em;
 | 
			
		||||
  height: 1em;
 | 
			
		||||
  fill: currentColor;
 | 
			
		||||
  vertical-align: middle;
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
// 卡片
 | 
			
		||||
.aui-card--fill .el-card__header {
 | 
			
		||||
  height: $content--card-header-height;
 | 
			
		||||
  line-height: $content--card-header-height - 36px;
 | 
			
		||||
}
 | 
			
		||||
.aui-card__title {
 | 
			
		||||
  font-size: 16px;
 | 
			
		||||
}
 | 
			
		||||
// 表单
 | 
			
		||||
.aui-form__label-icon {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
  margin: 0 3px;
 | 
			
		||||
  vertical-align: middle;
 | 
			
		||||
  font-size: 18px;
 | 
			
		||||
  color: $--color-text-secondary;
 | 
			
		||||
}
 | 
			
		||||
// 按钮
 | 
			
		||||
.aui-button--dashed {
 | 
			
		||||
  border-style: dashed;
 | 
			
		||||
  &:focus,
 | 
			
		||||
  &:hover {
 | 
			
		||||
    background-color: transparent;
 | 
			
		||||
  }
 | 
			
		||||
  &-add {
 | 
			
		||||
    > span > *[class*="el-icon-"],
 | 
			
		||||
    > span > *[class*="icon"] {
 | 
			
		||||
      vertical-align: middle;
 | 
			
		||||
      font-size: 18px;
 | 
			
		||||
      margin-right: 5px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
// 主题工具
 | 
			
		||||
.aui-theme-tools {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  top: $navbar--height + $content--tabs-header-height + 15px;
 | 
			
		||||
  right: -210px;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  z-index: 1010;
 | 
			
		||||
  width: 210px;
 | 
			
		||||
  transition: right 0.3s;
 | 
			
		||||
  &--open {
 | 
			
		||||
    right: 0;
 | 
			
		||||
  }
 | 
			
		||||
  &__toggle {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    top: 80px;
 | 
			
		||||
    left: -40px;
 | 
			
		||||
    width: 40px;
 | 
			
		||||
    padding: 10px 8px;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    font-size: 20px;
 | 
			
		||||
    border-right: 0;
 | 
			
		||||
    border-radius: $--border-radius-base 0 0 $--border-radius-base;
 | 
			
		||||
    color: #fff;
 | 
			
		||||
    background-color: $--color-primary;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
  }
 | 
			
		||||
  &__content {
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    padding: 5px 20px 20px;
 | 
			
		||||
    border: 1px solid $--border-color-lighter;
 | 
			
		||||
    border-radius: $--border-radius-base 0 0 $--border-radius-base;
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    .el-radio {
 | 
			
		||||
      display: block;
 | 
			
		||||
      margin-left: 0 !important;
 | 
			
		||||
      line-height: 28px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  &__item + &__item {
 | 
			
		||||
    margin-top: 15px;
 | 
			
		||||
    border-top: 1px solid $--border-color-lighter;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Layout
 | 
			
		||||
------------------------------ */
 | 
			
		||||
.aui-wrapper {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  padding-top: $navbar--height;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Sidebar fold
 | 
			
		||||
------------------------------ */
 | 
			
		||||
.aui-sidebar--fold {
 | 
			
		||||
  .aui-navbar {
 | 
			
		||||
    &__header,
 | 
			
		||||
    &__brand {
 | 
			
		||||
      width: $sidebar--width-fold;
 | 
			
		||||
    }
 | 
			
		||||
    &__brand {
 | 
			
		||||
      &-lg {
 | 
			
		||||
        display: none;
 | 
			
		||||
      }
 | 
			
		||||
      &-mini {
 | 
			
		||||
        display: inline-block;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    &__icon-menu--switch {
 | 
			
		||||
      transform: rotateZ(180deg);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .aui-sidebar {
 | 
			
		||||
    &__inner {
 | 
			
		||||
      width: $sidebar--width-fold + 20px;
 | 
			
		||||
    }
 | 
			
		||||
    &,
 | 
			
		||||
    &__menu {
 | 
			
		||||
      width: $sidebar--width-fold;
 | 
			
		||||
    }
 | 
			
		||||
    &__menu > li > .el-submenu__title {
 | 
			
		||||
      text-align: center;
 | 
			
		||||
    }
 | 
			
		||||
    &__menu-icon {
 | 
			
		||||
      margin-right: 0;
 | 
			
		||||
      font-size: 18px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .aui-content {
 | 
			
		||||
    &__wrapper {
 | 
			
		||||
      margin-left: $sidebar--width-fold;
 | 
			
		||||
    }
 | 
			
		||||
    &--tabs > .el-tabs > .el-tabs__header {
 | 
			
		||||
      left: $sidebar--width-fold;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Navbar
 | 
			
		||||
------------------------------ */
 | 
			
		||||
.aui-navbar {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  top: 0;
 | 
			
		||||
  right: 0;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  z-index: 1030;
 | 
			
		||||
  display: flex;
 | 
			
		||||
  align-items: stretch;
 | 
			
		||||
  height: $navbar--height;
 | 
			
		||||
  background-color: $--color-primary;
 | 
			
		||||
  box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.05);
 | 
			
		||||
  &--colorful {
 | 
			
		||||
    .aui-navbar__body {
 | 
			
		||||
    }
 | 
			
		||||
    .aui-navbar__menu {
 | 
			
		||||
      > .el-menu-item,
 | 
			
		||||
      > .el-submenu > .el-submenu__title {
 | 
			
		||||
        color: #fff;
 | 
			
		||||
        &:focus,
 | 
			
		||||
        &:hover {
 | 
			
		||||
          color: #fff;
 | 
			
		||||
          background-color: mix(#fff, $--color-primary, 15%);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      > .el-menu-item.is-active,
 | 
			
		||||
      > .el-submenu.is-active > .el-submenu__title {
 | 
			
		||||
        color: #fff;
 | 
			
		||||
        &:focus,
 | 
			
		||||
        &:hover {
 | 
			
		||||
          color: #fff;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      .el-menu-item i,
 | 
			
		||||
      .el-submenu__title i,
 | 
			
		||||
      .el-menu-item svg,
 | 
			
		||||
      .el-submenu__title svg,
 | 
			
		||||
      .el-menu-item .el-dropdown {
 | 
			
		||||
        color: grey;
 | 
			
		||||
      }
 | 
			
		||||
      .el-button {
 | 
			
		||||
        color: #fff;
 | 
			
		||||
        background-color: transparent;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    .aui-navbar__search {
 | 
			
		||||
      &-txt {
 | 
			
		||||
        .el-input__inner {
 | 
			
		||||
          color: #fff;
 | 
			
		||||
          border-color: #fff;
 | 
			
		||||
          &::-webkit-input-placeholder {
 | 
			
		||||
            color: #fff;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  &__header {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    width: $sidebar--width;
 | 
			
		||||
    height: $navbar--height;
 | 
			
		||||
    transition: width 0.3s;
 | 
			
		||||
  }
 | 
			
		||||
  &__brand {
 | 
			
		||||
    background-color: rgba(0, 21, 41, 1);
 | 
			
		||||
    display: flex;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    padding: 5px;
 | 
			
		||||
    margin: 0;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    font-size: 20px;
 | 
			
		||||
    text-transform: uppercase;
 | 
			
		||||
    white-space: nowrap;
 | 
			
		||||
    color: #fff;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
    transition: width 0.3s;
 | 
			
		||||
    &-lg,
 | 
			
		||||
    &-mini {
 | 
			
		||||
      max-width: 100%;
 | 
			
		||||
      color: #fff;
 | 
			
		||||
      cursor: pointer;
 | 
			
		||||
      &:focus,
 | 
			
		||||
      &:hover {
 | 
			
		||||
        color: #fff;
 | 
			
		||||
        text-decoration: none;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    &-mini {
 | 
			
		||||
      display: none;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  &__body {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex: 1;
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
  }
 | 
			
		||||
  &__menu {
 | 
			
		||||
    background-color: transparent;
 | 
			
		||||
    border-bottom: 0 !important;
 | 
			
		||||
    a:focus,
 | 
			
		||||
    a:hover {
 | 
			
		||||
      text-decoration: none;
 | 
			
		||||
    }
 | 
			
		||||
    .el-menu-item,
 | 
			
		||||
    .el-submenu > .el-submenu__title {
 | 
			
		||||
      height: $navbar--height;
 | 
			
		||||
      padding: 0 15px;
 | 
			
		||||
      line-height: $navbar--height;
 | 
			
		||||
      border-color: transparent !important;
 | 
			
		||||
    }
 | 
			
		||||
    .el-menu-item.is-active,
 | 
			
		||||
    .el-submenu.is-active > .el-submenu__title {
 | 
			
		||||
      color: $--color-text-secondary;
 | 
			
		||||
      &:focus,
 | 
			
		||||
      &:hover {
 | 
			
		||||
        color: $--color-text-primary;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    .el-menu-item {
 | 
			
		||||
      &:focus,
 | 
			
		||||
      &:hover {
 | 
			
		||||
        .aui-navbar__icon-menu {
 | 
			
		||||
          color: $--color-text-primary;
 | 
			
		||||
        }
 | 
			
		||||
        .el-dropdown {
 | 
			
		||||
          color: $--color-text-primary;
 | 
			
		||||
          .el-icon-arrow-down {
 | 
			
		||||
            transform: rotateZ(180deg);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      * {
 | 
			
		||||
        vertical-align: initial;
 | 
			
		||||
      }
 | 
			
		||||
      .aui-navbar__icon-menu {
 | 
			
		||||
        vertical-align: middle;
 | 
			
		||||
        font-size: 16px;
 | 
			
		||||
      }
 | 
			
		||||
      .el-dropdown {
 | 
			
		||||
        color: $--color-text-secondary;
 | 
			
		||||
        .el-icon-arrow-down {
 | 
			
		||||
          width: auto;
 | 
			
		||||
          font-size: 12px;
 | 
			
		||||
          margin: 0 0 0 5px;
 | 
			
		||||
          transition: transform 0.3s;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    .el-badge {
 | 
			
		||||
      display: inline;
 | 
			
		||||
      z-index: 2;
 | 
			
		||||
      &__content {
 | 
			
		||||
        line-height: 16px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  &__search {
 | 
			
		||||
    > *[class*="el-icon-"],
 | 
			
		||||
    > *[class*="icon"] {
 | 
			
		||||
      display: inline-block;
 | 
			
		||||
      vertical-align: middle;
 | 
			
		||||
    }
 | 
			
		||||
    &-txt {
 | 
			
		||||
      width: 0;
 | 
			
		||||
      transition: width 0.3s, margin-left 0.3s;
 | 
			
		||||
      &.is-show {
 | 
			
		||||
        width: 210px;
 | 
			
		||||
        margin-left: 8px;
 | 
			
		||||
      }
 | 
			
		||||
      .el-input__inner {
 | 
			
		||||
        height: $navbar--height - 20px;
 | 
			
		||||
        padding: 0;
 | 
			
		||||
        line-height: $navbar--height - 20px;
 | 
			
		||||
        border-color: $--color-text-primary;
 | 
			
		||||
        border-top: 0;
 | 
			
		||||
        border-right: 0;
 | 
			
		||||
        border-left: 0;
 | 
			
		||||
        border-radius: 0;
 | 
			
		||||
        background: transparent;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  &__avatar {
 | 
			
		||||
    .el-dropdown-link {
 | 
			
		||||
      > img {
 | 
			
		||||
        width: 36px;
 | 
			
		||||
        height: auto;
 | 
			
		||||
        margin-right: 5px;
 | 
			
		||||
        border-radius: 100%;
 | 
			
		||||
        vertical-align: middle;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Sidebar
 | 
			
		||||
------------------------------ */
 | 
			
		||||
.aui-sidebar {
 | 
			
		||||
  position: fixed;
 | 
			
		||||
  top: $navbar--height;
 | 
			
		||||
  left: 0;
 | 
			
		||||
  bottom: 0;
 | 
			
		||||
  z-index: 1020;
 | 
			
		||||
  width: $sidebar--width;
 | 
			
		||||
  background-color: #fff;
 | 
			
		||||
  box-shadow: 1px 0 2px 0 rgba(0, 0, 0, 0.05);
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
  transition: width 0.3s;
 | 
			
		||||
  &--dark {
 | 
			
		||||
    background-color: $sidebar--background-color-dark;
 | 
			
		||||
    .aui-sidebar__menu,
 | 
			
		||||
    > .el-menu--popup {
 | 
			
		||||
      background-color: $sidebar--background-color-dark;
 | 
			
		||||
      .el-menu-item,
 | 
			
		||||
      .el-submenu > .el-submenu__title {
 | 
			
		||||
        color: $sidebar--text-color-dark;
 | 
			
		||||
        &:focus,
 | 
			
		||||
        &:hover {
 | 
			
		||||
          color: #fff;
 | 
			
		||||
          background-color: rgba(11, 88, 255, 1);
 | 
			
		||||
          .aui-sidebar__menu-icon-son{
 | 
			
		||||
            background: #fff;
 | 
			
		||||
            border-radius: 4px;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      .el-menu,
 | 
			
		||||
      .el-submenu.is-opened {
 | 
			
		||||
        background-color: rgba(11, 37, 63, 1);
 | 
			
		||||
      }
 | 
			
		||||
      .el-menu-item.is-active,
 | 
			
		||||
      .el-submenu.is-active > .el-submenu__title {
 | 
			
		||||
        color: #fff;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  &__inner {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    z-index: 1;
 | 
			
		||||
    width: $sidebar--width + 20px;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    padding-bottom: 15px;
 | 
			
		||||
    overflow-x: hidden;
 | 
			
		||||
    overflow-y: scroll;
 | 
			
		||||
    transition: width 0.3s;
 | 
			
		||||
  }
 | 
			
		||||
  &__menu {
 | 
			
		||||
    width: $sidebar--width;
 | 
			
		||||
    border-right: 0;
 | 
			
		||||
    transition: width 0.3s;
 | 
			
		||||
    .el-menu-item,
 | 
			
		||||
    .el-submenu__title {
 | 
			
		||||
      height: $sidebar--menu-item-height;
 | 
			
		||||
      line-height: $sidebar--menu-item-height;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  &__menu-icon {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
    width: 24px !important;
 | 
			
		||||
    margin-right: 5px;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    font-size: 16px;
 | 
			
		||||
    color: inherit !important;
 | 
			
		||||
    transition: font-size 0.3s;
 | 
			
		||||
  }
 | 
			
		||||
  &__menu-icon-son {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
    width: 8px !important;
 | 
			
		||||
    margin-right: 15px;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    font-size: 8px;
 | 
			
		||||
    color: inherit !important;
 | 
			
		||||
    transition: font-size 0.3s;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Content
 | 
			
		||||
------------------------------ */
 | 
			
		||||
.aui-content {
 | 
			
		||||
  position: relative;
 | 
			
		||||
  padding: $content--padding;
 | 
			
		||||
  min-height: calc(100vh - #{$navbar--height});
 | 
			
		||||
  &__wrapper {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    margin-left: $sidebar--width;
 | 
			
		||||
    min-height: calc(100vh - #{$navbar--height});
 | 
			
		||||
    background-color: $content--background-color;
 | 
			
		||||
    transition: margin-left 0.3s;
 | 
			
		||||
  }
 | 
			
		||||
  > .aui-card--fill > .el-card__body {
 | 
			
		||||
    min-height: calc(#{$content--fill-height} - 2px);
 | 
			
		||||
  }
 | 
			
		||||
  > .aui-card--fill > .el-card__header + .el-card__body {
 | 
			
		||||
    min-height: calc(#{$content--fill-height} - #{$content--card-header-height} - 2px);
 | 
			
		||||
  }
 | 
			
		||||
  &--tabs {
 | 
			
		||||
    padding: $content--tabs-header-height 0 0;
 | 
			
		||||
  }
 | 
			
		||||
  &--tabs-tools {
 | 
			
		||||
    position: fixed;
 | 
			
		||||
    top: $navbar--height;
 | 
			
		||||
    right: 0;
 | 
			
		||||
    z-index: 931;
 | 
			
		||||
    min-width: $content--tabs-header-height;
 | 
			
		||||
    height: $content--tabs-header-height;
 | 
			
		||||
    padding: 0 12px;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    font-size: 16px;
 | 
			
		||||
    line-height: $content--tabs-header-height;
 | 
			
		||||
    background-color: $--background-color-base;
 | 
			
		||||
    cursor: pointer;
 | 
			
		||||
  }
 | 
			
		||||
  &--tabs-icon-nav {
 | 
			
		||||
    display: inline-block;
 | 
			
		||||
    vertical-align: middle;
 | 
			
		||||
    font-size: 16px;
 | 
			
		||||
  }
 | 
			
		||||
  > .el-tabs {
 | 
			
		||||
    > .el-tabs__header {
 | 
			
		||||
      position: fixed;
 | 
			
		||||
      top: $navbar--height;
 | 
			
		||||
      left: $sidebar--width;
 | 
			
		||||
      right: 0;
 | 
			
		||||
      z-index: 930;
 | 
			
		||||
      padding: 0 55px 0 15px;
 | 
			
		||||
      margin: 0;
 | 
			
		||||
      box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
 | 
			
		||||
      background-color: #fff;
 | 
			
		||||
      transition: left 0.3s;
 | 
			
		||||
      > .el-tabs__nav-wrap {
 | 
			
		||||
        margin-bottom: 0;
 | 
			
		||||
        &:after {
 | 
			
		||||
          display: none;
 | 
			
		||||
        }
 | 
			
		||||
        > .el-tabs__nav-next,
 | 
			
		||||
        > .el-tabs__nav-prev {
 | 
			
		||||
          line-height: $content--tabs-header-height;
 | 
			
		||||
        }
 | 
			
		||||
        > .el-tabs__nav-scroll > .el-tabs__nav {
 | 
			
		||||
          & > .el-tabs__active-bar {
 | 
			
		||||
            display: none;
 | 
			
		||||
          }
 | 
			
		||||
          & > .el-tabs__item {
 | 
			
		||||
            height: $content--tabs-header-height;
 | 
			
		||||
            border: 0;
 | 
			
		||||
            padding: 0 10px;
 | 
			
		||||
            color: rgba(89, 89, 89, 1);
 | 
			
		||||
            &:focus,
 | 
			
		||||
            &:hover,
 | 
			
		||||
            &.is-active {
 | 
			
		||||
              &:after {
 | 
			
		||||
                display: block;
 | 
			
		||||
              }
 | 
			
		||||
              > .el-icon-close {
 | 
			
		||||
                color: rgba(255, 255, 255, 1);
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
            &:after {
 | 
			
		||||
              display: none;
 | 
			
		||||
              position: absolute;
 | 
			
		||||
              bottom: 0;
 | 
			
		||||
              left: 0;
 | 
			
		||||
              content: "";
 | 
			
		||||
              width: 100%;
 | 
			
		||||
              height: 2px;
 | 
			
		||||
              background-color: $--color-primary;
 | 
			
		||||
            }
 | 
			
		||||
            + .el-tabs__item {
 | 
			
		||||
              margin-left: 5px;
 | 
			
		||||
              height: 24px;
 | 
			
		||||
              font-size: 12px;
 | 
			
		||||
              line-height: 24px;
 | 
			
		||||
              border-radius: 5px;
 | 
			
		||||
              background-color: rgba(239, 239, 239, 1);
 | 
			
		||||
              &.is-active {
 | 
			
		||||
                color: rgba(255, 255, 255, 1);
 | 
			
		||||
                background-color: rgba(62, 142, 247, 1);
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
            > .el-icon-close {
 | 
			
		||||
              width: 14px;
 | 
			
		||||
              margin-left: 6px;
 | 
			
		||||
              color: $--color-text-secondary;
 | 
			
		||||
            }
 | 
			
		||||
            > i.icon {
 | 
			
		||||
              display: inline-block;
 | 
			
		||||
              vertical-align: middle;
 | 
			
		||||
              font-size: 18px;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    > .el-tabs__content {
 | 
			
		||||
      padding: $content--padding;
 | 
			
		||||
      .el-loading-mask {
 | 
			
		||||
        z-index: 830;
 | 
			
		||||
      }
 | 
			
		||||
      > .el-tab-pane {
 | 
			
		||||
        min-height: calc(#{$content--fill-height-tabs});
 | 
			
		||||
        > .aui-card--fill > .el-card__body {
 | 
			
		||||
          min-height: calc(#{$content--fill-height-tabs} - 2px);
 | 
			
		||||
        }
 | 
			
		||||
        > .aui-card--fill > .el-card__header + .el-card__body {
 | 
			
		||||
          min-height: calc(#{$content--fill-height-tabs} - #{$content--card-header-height} - 2px);
 | 
			
		||||
        }
 | 
			
		||||
        &.is-iframe {
 | 
			
		||||
          height: calc(#{$content--fill-height-tabs} + #{$content--padding * 2});
 | 
			
		||||
          margin: -$content--padding;
 | 
			
		||||
          min-height: auto;
 | 
			
		||||
          > .aui-card--fill {
 | 
			
		||||
            background-color: transparent;
 | 
			
		||||
          }
 | 
			
		||||
          > .aui-card--fill > .el-card__header {
 | 
			
		||||
            background-color: #fff;
 | 
			
		||||
          }
 | 
			
		||||
          > .aui-card--fill > .el-card__body {
 | 
			
		||||
            height: calc(#{$content--fill-height-tabs} - 2px);
 | 
			
		||||
            margin: $content--padding;
 | 
			
		||||
            min-height: auto;
 | 
			
		||||
            border: $--border-base;
 | 
			
		||||
            border-color: $--border-color-lighter;
 | 
			
		||||
            border-radius: $--border-radius-base;
 | 
			
		||||
            background-color: #fff;
 | 
			
		||||
          }
 | 
			
		||||
          > .aui-card--fill > .el-card__header + .el-card__body {
 | 
			
		||||
            height: calc(#{$content--fill-height-tabs} - #{$content--card-header-height} - 2px);
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // quill富文本编辑器
 | 
			
		||||
  .ql-toolbar {
 | 
			
		||||
    line-height: 20px;
 | 
			
		||||
    &.ql-snow {
 | 
			
		||||
      border-color: $--border-color-base;
 | 
			
		||||
    }
 | 
			
		||||
    .ql-formats {
 | 
			
		||||
      margin: 0 5px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .ql-container {
 | 
			
		||||
    height: 150px;
 | 
			
		||||
    &.ql-snow {
 | 
			
		||||
      border-color: $--border-color-base;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Page
 | 
			
		||||
------------------------------ */
 | 
			
		||||
*[class*="aui-page__"] {
 | 
			
		||||
  padding-top: 0;
 | 
			
		||||
  .aui-content {
 | 
			
		||||
    min-height: auto;
 | 
			
		||||
    &__wrapper {
 | 
			
		||||
      min-height: 100vh;
 | 
			
		||||
      margin-left: 0;
 | 
			
		||||
    }
 | 
			
		||||
    > .aui-card--fill > .el-card__body {
 | 
			
		||||
      min-height: calc(100vh - #{$content--padding * 2} - 2px);
 | 
			
		||||
    }
 | 
			
		||||
    > .aui-card--fill > .el-card__header + .el-card__body {
 | 
			
		||||
      min-height: calc(100vh - #{$content--padding * 2} - #{$content--card-header-height} - 2px);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										15
									
								
								src/assets/scss/modules/home.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,15 @@
 | 
			
		||||
.mod-home {
 | 
			
		||||
  table {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    border: 1px solid $--border-color-lighter;
 | 
			
		||||
    border-collapse: collapse;
 | 
			
		||||
    th,
 | 
			
		||||
    td {
 | 
			
		||||
      padding: 12px 10px;
 | 
			
		||||
      border: 1px solid $--border-color-lighter;
 | 
			
		||||
    }
 | 
			
		||||
    th {
 | 
			
		||||
      width: 30%;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										447
									
								
								src/assets/scss/normalize.scss
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,447 @@
 | 
			
		||||
/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */
 | 
			
		||||
 | 
			
		||||
/* Document
 | 
			
		||||
   ========================================================================== */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Correct the line height in all browsers.
 | 
			
		||||
 * 2. Prevent adjustments of font size after orientation changes in
 | 
			
		||||
 *    IE on Windows Phone and in iOS.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 html {
 | 
			
		||||
  line-height: 1.15; /* 1 */
 | 
			
		||||
  -ms-text-size-adjust: 100%; /* 2 */
 | 
			
		||||
  -webkit-text-size-adjust: 100%; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Sections
 | 
			
		||||
   ========================================================================== */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Remove the margin in all browsers (opinionated).
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
body {
 | 
			
		||||
  margin: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add the correct display in IE 9-.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
article,
 | 
			
		||||
aside,
 | 
			
		||||
footer,
 | 
			
		||||
header,
 | 
			
		||||
nav,
 | 
			
		||||
section {
 | 
			
		||||
  display: block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Correct the font size and margin on `h1` elements within `section` and
 | 
			
		||||
 * `article` contexts in Chrome, Firefox, and Safari.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
h1 {
 | 
			
		||||
  font-size: 2em;
 | 
			
		||||
  margin: 0.67em 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Grouping content
 | 
			
		||||
   ========================================================================== */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add the correct display in IE 9-.
 | 
			
		||||
 * 1. Add the correct display in IE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
figcaption,
 | 
			
		||||
figure,
 | 
			
		||||
main { /* 1 */
 | 
			
		||||
  display: block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add the correct margin in IE 8.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
figure {
 | 
			
		||||
  margin: 1em 40px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Add the correct box sizing in Firefox.
 | 
			
		||||
 * 2. Show the overflow in Edge and IE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
hr {
 | 
			
		||||
  box-sizing: content-box; /* 1 */
 | 
			
		||||
  height: 0; /* 1 */
 | 
			
		||||
  overflow: visible; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Correct the inheritance and scaling of font size in all browsers.
 | 
			
		||||
 * 2. Correct the odd `em` font sizing in all browsers.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
pre {
 | 
			
		||||
  font-family: monospace, monospace; /* 1 */
 | 
			
		||||
  font-size: 1em; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Text-level semantics
 | 
			
		||||
   ========================================================================== */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Remove the gray background on active links in IE 10.
 | 
			
		||||
 * 2. Remove gaps in links underline in iOS 8+ and Safari 8+.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
a {
 | 
			
		||||
  background-color: transparent; /* 1 */
 | 
			
		||||
  -webkit-text-decoration-skip: objects; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Remove the bottom border in Chrome 57- and Firefox 39-.
 | 
			
		||||
 * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
abbr[title] {
 | 
			
		||||
  border-bottom: none; /* 1 */
 | 
			
		||||
  text-decoration: underline; /* 2 */
 | 
			
		||||
  text-decoration: underline dotted; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Prevent the duplicate application of `bolder` by the next rule in Safari 6.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
b,
 | 
			
		||||
strong {
 | 
			
		||||
  font-weight: inherit;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add the correct font weight in Chrome, Edge, and Safari.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
b,
 | 
			
		||||
strong {
 | 
			
		||||
  font-weight: bolder;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Correct the inheritance and scaling of font size in all browsers.
 | 
			
		||||
 * 2. Correct the odd `em` font sizing in all browsers.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
code,
 | 
			
		||||
kbd,
 | 
			
		||||
samp {
 | 
			
		||||
  font-family: monospace, monospace; /* 1 */
 | 
			
		||||
  font-size: 1em; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add the correct font style in Android 4.3-.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
dfn {
 | 
			
		||||
  font-style: italic;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add the correct background and color in IE 9-.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
mark {
 | 
			
		||||
  background-color: #ff0;
 | 
			
		||||
  color: #000;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add the correct font size in all browsers.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
small {
 | 
			
		||||
  font-size: 80%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Prevent `sub` and `sup` elements from affecting the line height in
 | 
			
		||||
 * all browsers.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
sub,
 | 
			
		||||
sup {
 | 
			
		||||
  font-size: 75%;
 | 
			
		||||
  line-height: 0;
 | 
			
		||||
  position: relative;
 | 
			
		||||
  vertical-align: baseline;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sub {
 | 
			
		||||
  bottom: -0.25em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
sup {
 | 
			
		||||
  top: -0.5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Embedded content
 | 
			
		||||
   ========================================================================== */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add the correct display in IE 9-.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
audio,
 | 
			
		||||
video {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add the correct display in iOS 4-7.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
audio:not([controls]) {
 | 
			
		||||
  display: none;
 | 
			
		||||
  height: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Remove the border on images inside links in IE 10-.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
img {
 | 
			
		||||
  border-style: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Hide the overflow in IE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
svg:not(:root) {
 | 
			
		||||
  overflow: hidden;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Forms
 | 
			
		||||
   ========================================================================== */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Change the font styles in all browsers (opinionated).
 | 
			
		||||
 * 2. Remove the margin in Firefox and Safari.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
button,
 | 
			
		||||
input,
 | 
			
		||||
optgroup,
 | 
			
		||||
select,
 | 
			
		||||
textarea {
 | 
			
		||||
  font-family: sans-serif; /* 1 */
 | 
			
		||||
  font-size: 100%; /* 1 */
 | 
			
		||||
  line-height: 1.15; /* 1 */
 | 
			
		||||
  margin: 0; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Show the overflow in IE.
 | 
			
		||||
 * 1. Show the overflow in Edge.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
button,
 | 
			
		||||
input { /* 1 */
 | 
			
		||||
  overflow: visible;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Remove the inheritance of text transform in Edge, Firefox, and IE.
 | 
			
		||||
 * 1. Remove the inheritance of text transform in Firefox.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
button,
 | 
			
		||||
select { /* 1 */
 | 
			
		||||
  text-transform: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
 | 
			
		||||
 *    controls in Android 4.
 | 
			
		||||
 * 2. Correct the inability to style clickable types in iOS and Safari.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
button,
 | 
			
		||||
html [type="button"], /* 1 */
 | 
			
		||||
[type="reset"],
 | 
			
		||||
[type="submit"] {
 | 
			
		||||
  -webkit-appearance: button; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Remove the inner border and padding in Firefox.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
button::-moz-focus-inner,
 | 
			
		||||
[type="button"]::-moz-focus-inner,
 | 
			
		||||
[type="reset"]::-moz-focus-inner,
 | 
			
		||||
[type="submit"]::-moz-focus-inner {
 | 
			
		||||
  border-style: none;
 | 
			
		||||
  padding: 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Restore the focus styles unset by the previous rule.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
button:-moz-focusring,
 | 
			
		||||
[type="button"]:-moz-focusring,
 | 
			
		||||
[type="reset"]:-moz-focusring,
 | 
			
		||||
[type="submit"]:-moz-focusring {
 | 
			
		||||
  outline: 1px dotted ButtonText;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Correct the padding in Firefox.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
fieldset {
 | 
			
		||||
  padding: 0.35em 0.75em 0.625em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Correct the text wrapping in Edge and IE.
 | 
			
		||||
 * 2. Correct the color inheritance from `fieldset` elements in IE.
 | 
			
		||||
 * 3. Remove the padding so developers are not caught out when they zero out
 | 
			
		||||
 *    `fieldset` elements in all browsers.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
legend {
 | 
			
		||||
  box-sizing: border-box; /* 1 */
 | 
			
		||||
  color: inherit; /* 2 */
 | 
			
		||||
  display: table; /* 1 */
 | 
			
		||||
  max-width: 100%; /* 1 */
 | 
			
		||||
  padding: 0; /* 3 */
 | 
			
		||||
  white-space: normal; /* 1 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Add the correct display in IE 9-.
 | 
			
		||||
 * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
progress {
 | 
			
		||||
  display: inline-block; /* 1 */
 | 
			
		||||
  vertical-align: baseline; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Remove the default vertical scrollbar in IE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
textarea {
 | 
			
		||||
  overflow: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Add the correct box sizing in IE 10-.
 | 
			
		||||
 * 2. Remove the padding in IE 10-.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
[type="checkbox"],
 | 
			
		||||
[type="radio"] {
 | 
			
		||||
  box-sizing: border-box; /* 1 */
 | 
			
		||||
  padding: 0; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Correct the cursor style of increment and decrement buttons in Chrome.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
[type="number"]::-webkit-inner-spin-button,
 | 
			
		||||
[type="number"]::-webkit-outer-spin-button {
 | 
			
		||||
  height: auto;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Correct the odd appearance in Chrome and Safari.
 | 
			
		||||
 * 2. Correct the outline style in Safari.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
[type="search"] {
 | 
			
		||||
  -webkit-appearance: textfield; /* 1 */
 | 
			
		||||
  outline-offset: -2px; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Remove the inner padding and cancel buttons in Chrome and Safari on macOS.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
[type="search"]::-webkit-search-cancel-button,
 | 
			
		||||
[type="search"]::-webkit-search-decoration {
 | 
			
		||||
  -webkit-appearance: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * 1. Correct the inability to style clickable types in iOS and Safari.
 | 
			
		||||
 * 2. Change font properties to `inherit` in Safari.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
::-webkit-file-upload-button {
 | 
			
		||||
  -webkit-appearance: button; /* 1 */
 | 
			
		||||
  font: inherit; /* 2 */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Interactive
 | 
			
		||||
   ========================================================================== */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Add the correct display in IE 9-.
 | 
			
		||||
 * 1. Add the correct display in Edge, IE, and Firefox.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
details, /* 1 */
 | 
			
		||||
menu {
 | 
			
		||||
  display: block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Add the correct display in all browsers.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
summary {
 | 
			
		||||
  display: list-item;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Scripting
 | 
			
		||||
   ========================================================================== */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add the correct display in IE 9-.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
canvas {
 | 
			
		||||
  display: inline-block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add the correct display in IE.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
template {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* Hidden
 | 
			
		||||
   ========================================================================== */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Add the correct display in IE 10-.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
[hidden] {
 | 
			
		||||
  display: none;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										48
									
								
								src/assets/scss/pages/404.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,48 @@
 | 
			
		||||
.aui-page__not-found {
 | 
			
		||||
  .aui-content {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-flow: column wrap;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    min-height: 100vh;
 | 
			
		||||
    padding: 15% 50px 50px;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    &__wrapper {
 | 
			
		||||
      height: 100vh;
 | 
			
		||||
      background-color: transparent;
 | 
			
		||||
      overflow-x: hidden;
 | 
			
		||||
      overflow-y: auto;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .title {
 | 
			
		||||
    margin: 0 0 15px;
 | 
			
		||||
    font-size: 10em;
 | 
			
		||||
    font-weight: 400;
 | 
			
		||||
    color: $--color-text-regular;
 | 
			
		||||
  }
 | 
			
		||||
  .desc {
 | 
			
		||||
    margin: 0 0 20px;
 | 
			
		||||
    font-size: 26px;
 | 
			
		||||
    color: $--color-text-secondary;
 | 
			
		||||
    > em {
 | 
			
		||||
      margin: 0 5px;
 | 
			
		||||
      font-style: normal;
 | 
			
		||||
      color: $--color-warning;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .btn-bar .el-button {
 | 
			
		||||
    margin: 0 15px;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@media (max-width: 767px) {
 | 
			
		||||
  .aui-page__not-found {
 | 
			
		||||
    .title {
 | 
			
		||||
      font-size: 8em;
 | 
			
		||||
    }
 | 
			
		||||
    .desc {
 | 
			
		||||
      font-size: 20px;
 | 
			
		||||
    }
 | 
			
		||||
    .btn-bar .el-button {
 | 
			
		||||
      margin: 0 7.5px;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										220
									
								
								src/assets/scss/pages/login.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,220 @@
 | 
			
		||||
.aui-page__login {
 | 
			
		||||
  &::before,
 | 
			
		||||
  &::after {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    top: 0;
 | 
			
		||||
    right: 0;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    z-index: -1;
 | 
			
		||||
    content: "";
 | 
			
		||||
  }
 | 
			
		||||
  &::before {
 | 
			
		||||
    background-image: url(~@/assets/img/login_bg.jpg);
 | 
			
		||||
    background-size: cover;
 | 
			
		||||
  }
 | 
			
		||||
  &::after {
 | 
			
		||||
    background-color: rgba(38, 50, 56, .4);
 | 
			
		||||
  }
 | 
			
		||||
  .aui-content {
 | 
			
		||||
    display: flex;
 | 
			
		||||
    flex-flow: column wrap;
 | 
			
		||||
    justify-content: center;
 | 
			
		||||
    align-items: center;
 | 
			
		||||
    min-height: 100vh;
 | 
			
		||||
    padding: 50px 20px 150px;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    &__wrapper {
 | 
			
		||||
      height: 100vh;
 | 
			
		||||
      background-color: transparent;
 | 
			
		||||
      overflow-x: hidden;
 | 
			
		||||
      overflow-y: auto;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .login-header {
 | 
			
		||||
    padding: 20px;
 | 
			
		||||
    color: #fff;
 | 
			
		||||
    .login-brand {
 | 
			
		||||
      margin: 0 0 15px;
 | 
			
		||||
      font-size: 40px;
 | 
			
		||||
      font-weight: 400;
 | 
			
		||||
      letter-spacing: 2px;
 | 
			
		||||
      text-transform: uppercase;
 | 
			
		||||
    }
 | 
			
		||||
    .login-intro {
 | 
			
		||||
      padding: 0;
 | 
			
		||||
      margin: 0;
 | 
			
		||||
      list-style: none;
 | 
			
		||||
      > li {
 | 
			
		||||
        font-size: 16px;
 | 
			
		||||
        line-height: 1.5;
 | 
			
		||||
        color: rgba(255, 255, 255, .6);
 | 
			
		||||
        & + li {
 | 
			
		||||
          margin-top: 5px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .login-body,
 | 
			
		||||
  .login-footer {
 | 
			
		||||
    width: 460px;
 | 
			
		||||
  }
 | 
			
		||||
  .login-body {
 | 
			
		||||
    padding: 20px 30px;
 | 
			
		||||
    background-color: #fff;
 | 
			
		||||
    .login-title {
 | 
			
		||||
      font-size: 18px;
 | 
			
		||||
      font-weight: 400;
 | 
			
		||||
    }
 | 
			
		||||
    .el-input__prefix .el-input__icon {
 | 
			
		||||
      font-size: 16px;
 | 
			
		||||
    }
 | 
			
		||||
    .login-captcha {
 | 
			
		||||
      height: $--input-height;
 | 
			
		||||
      line-height: $--input-height -2px;
 | 
			
		||||
      > img {
 | 
			
		||||
        max-width: 100%;
 | 
			
		||||
        cursor: pointer;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    .login-shortcut {
 | 
			
		||||
      margin-bottom: 20px;
 | 
			
		||||
      &__title {
 | 
			
		||||
        position: relative;
 | 
			
		||||
        margin: 0 0 15px;
 | 
			
		||||
        font-weight: 400;
 | 
			
		||||
        
 | 
			
		||||
        &::before {
 | 
			
		||||
          position: absolute;
 | 
			
		||||
          top: 50%;
 | 
			
		||||
          right: 0;
 | 
			
		||||
          left: 0;
 | 
			
		||||
          z-index: 1;
 | 
			
		||||
          content: "";
 | 
			
		||||
          height: 1px;
 | 
			
		||||
          margin-top: -.5px;
 | 
			
		||||
          background-color: $--border-color-base;
 | 
			
		||||
          overflow: hidden;
 | 
			
		||||
        }
 | 
			
		||||
        > span {
 | 
			
		||||
          position: relative;
 | 
			
		||||
          z-index: 2;
 | 
			
		||||
          padding: 0 20px;
 | 
			
		||||
          color: rgba(0, 0, 0, .3);
 | 
			
		||||
          background-color: #fff;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      &__list {
 | 
			
		||||
        padding: 0;
 | 
			
		||||
        margin: 0;
 | 
			
		||||
        list-style: none;
 | 
			
		||||
        font-size: 0;
 | 
			
		||||
        > li {
 | 
			
		||||
          display: inline-block;
 | 
			
		||||
          vertical-align: middle;
 | 
			
		||||
          margin: 0 10px;
 | 
			
		||||
          font-size: 28px;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    .login-guide {
 | 
			
		||||
      color: rgba(0, 0, 0, .3);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  .login-footer {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    padding: 20px;
 | 
			
		||||
    color: rgba(255, 255, 255, .6);
 | 
			
		||||
    p {
 | 
			
		||||
      margin: 10px 0;
 | 
			
		||||
    }
 | 
			
		||||
    a {
 | 
			
		||||
      padding: 0 5px;
 | 
			
		||||
      color: rgba(255, 255, 255, .6);
 | 
			
		||||
      &:focus,
 | 
			
		||||
      &:hover {
 | 
			
		||||
        color: #fff;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  // 右侧垂直风格
 | 
			
		||||
  &--right-vertical {
 | 
			
		||||
    .aui-content {
 | 
			
		||||
      flex-flow: row nowrap;
 | 
			
		||||
      justify-content: flex-start;
 | 
			
		||||
      align-items: stretch;
 | 
			
		||||
      padding: 0;
 | 
			
		||||
    }
 | 
			
		||||
    .login-header {
 | 
			
		||||
      flex: 1;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      flex-flow: column wrap;
 | 
			
		||||
      justify-content: center;
 | 
			
		||||
      padding: 30px 120px;
 | 
			
		||||
      text-align: left;
 | 
			
		||||
    }
 | 
			
		||||
    .login-body {
 | 
			
		||||
      position: relative;
 | 
			
		||||
      display: flex;
 | 
			
		||||
      flex-flow: column wrap;
 | 
			
		||||
      justify-content: center;
 | 
			
		||||
      padding: 120px 30px 150px;
 | 
			
		||||
      text-align: center;
 | 
			
		||||
      .login-guide {
 | 
			
		||||
        margin-top: 0;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    .login-footer {
 | 
			
		||||
      right: 0;
 | 
			
		||||
      color: $--color-text-regular;
 | 
			
		||||
      a {
 | 
			
		||||
        color: $--color-text-regular;
 | 
			
		||||
        &:focus,
 | 
			
		||||
        &:hover {
 | 
			
		||||
          color: $--color-primary;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@media (max-width: 991px) {
 | 
			
		||||
  .aui-page__login {
 | 
			
		||||
    &--right-vertical {
 | 
			
		||||
      .login-header {
 | 
			
		||||
        padding: 30px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@media (max-width: 767px) {
 | 
			
		||||
  .aui-page__login {
 | 
			
		||||
    &--right-vertical {
 | 
			
		||||
      .login-header {
 | 
			
		||||
        .login-brand,
 | 
			
		||||
        .login-intro {
 | 
			
		||||
          display: none;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@media (max-width: 575px) {
 | 
			
		||||
  .aui-page__login {
 | 
			
		||||
    .login-body,
 | 
			
		||||
    .login-footer {
 | 
			
		||||
      width: 100%;
 | 
			
		||||
    }
 | 
			
		||||
    .login-captcha {
 | 
			
		||||
      text-align: left;
 | 
			
		||||
      > img {
 | 
			
		||||
        width: 136px;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    &--right-vertical {
 | 
			
		||||
      .login-header {
 | 
			
		||||
        display: none;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										22
									
								
								src/assets/scss/variables.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,22 @@
 | 
			
		||||
// Base
 | 
			
		||||
$base--line-height: 1.15;
 | 
			
		||||
 | 
			
		||||
// Navbar
 | 
			
		||||
$navbar--height: 50px;
 | 
			
		||||
 | 
			
		||||
// Sidebar
 | 
			
		||||
$sidebar--width: 248px;
 | 
			
		||||
$sidebar--width-fold: 64px;
 | 
			
		||||
$sidebar--background-color-dark: rgba(0, 21, 41, 1);
 | 
			
		||||
$sidebar--text-color-dark: rgba(255, 255, 255, 1);
 | 
			
		||||
$sidebar--menu-item-height: 48px;
 | 
			
		||||
 | 
			
		||||
// Content
 | 
			
		||||
$content--padding: 15px; 
 | 
			
		||||
$content--background-color: #f1f4f5;
 | 
			
		||||
$content--card-header-height: 60px;
 | 
			
		||||
$content--tabs-header-height: 38px;
 | 
			
		||||
// Content, 填充整屏高度(非tabs状态) = 整屏高度 - 导航条高度 - aui-content上下内边距高度
 | 
			
		||||
$content--fill-height: calc(100vh - #{$navbar--height} - #{$content--padding * 2});
 | 
			
		||||
// Content, 填充整屏高度(是tabs状态) = 整屏高度 - 导航条高度 - tabs组件header高度 - tabs组件content上下内边距高度
 | 
			
		||||
$content--fill-height-tabs: calc(100vh - #{$navbar--height} - #{$content--tabs-header-height} - #{$content--padding * 2});
 | 
			
		||||
							
								
								
									
										0
									
								
								src/components/.gitkeep
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										301
									
								
								src/components/AttrForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,301 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="attr-form">
 | 
			
		||||
		<h3>
 | 
			
		||||
			{{ title }} <el-button style="margin-left: 8px;" type="text" v-if="!isDetail && !showAddAttr" @click="showAddAttr = true">{{ $t('add') }}</el-button>
 | 
			
		||||
		</h3>
 | 
			
		||||
		<div v-if="!showAddAttr">
 | 
			
		||||
			<component
 | 
			
		||||
				key="sub-table"
 | 
			
		||||
				:is="require('./BaseTable.vue').default"
 | 
			
		||||
				:table-head-configs="filterTableConfigs()"
 | 
			
		||||
				:data="dataList"
 | 
			
		||||
				:page="pageIndex"
 | 
			
		||||
				:size="pageSize"
 | 
			
		||||
				:max-height="calcMaxHeight(8)"
 | 
			
		||||
				@operate-event="handleOperations"
 | 
			
		||||
			/>
 | 
			
		||||
			<el-pagination
 | 
			
		||||
				@size-change="sizeChangeHandle"
 | 
			
		||||
				@current-change="currentChangeHandle"
 | 
			
		||||
				:current-page="pageIndex"
 | 
			
		||||
				:page-sizes="[5, 10, 20, 50]"
 | 
			
		||||
				:page-size="pageSize"
 | 
			
		||||
				:total="totalPage"
 | 
			
		||||
				layout="total, sizes, prev, pager, next, jumper"
 | 
			
		||||
			>
 | 
			
		||||
			</el-pagination>
 | 
			
		||||
		</div>
 | 
			
		||||
		<div v-else style="background: #eee; border-radius: 8px; padding: 12px;">
 | 
			
		||||
			<el-row>
 | 
			
		||||
				<el-col>
 | 
			
		||||
					<el-form ref="AttrForm" :model="AttrForm" :rules="AttrFormRules" :inline="true" label-position="top">
 | 
			
		||||
						<el-row :gutter="20" style="padding: 0 24px;">
 | 
			
		||||
							<el-col :span="attrFormFields.length > 6 ? 6 : 12" v-for="field in attrFormFields" :key="field.prop + 'col'">
 | 
			
		||||
								<el-form-item :key="field.prop" :prop="field.prop" :label="field.name" style="width: 100%">
 | 
			
		||||
									<el-input v-if="field.formType === 'input' || !field.formType" v-model="AttrForm[field.prop]" :placeholder="$t('hints.input')" clearable />
 | 
			
		||||
									<el-select v-if="field.formType === 'select'" v-model="AttrForm[field.prop]" clearable>
 | 
			
		||||
										<el-option v-for="opt in field.formOptions" :key="opt.value" :label="opt.label" :value="opt.value" />
 | 
			
		||||
									</el-select>
 | 
			
		||||
									<!-- add more...  -->
 | 
			
		||||
								</el-form-item>
 | 
			
		||||
							</el-col>
 | 
			
		||||
						</el-row>
 | 
			
		||||
					</el-form>
 | 
			
		||||
				</el-col>
 | 
			
		||||
			</el-row>
 | 
			
		||||
			<el-row style="text-align: right;">
 | 
			
		||||
				<el-button size="small" @click="handleCloseAttrForm">{{ $t('cancel') }}</el-button>
 | 
			
		||||
				<el-button type="success" size="small" @click="handleSaveAttrForm">{{ $t('save') }}</el-button>
 | 
			
		||||
			</el-row>
 | 
			
		||||
		</div>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import i18n from '@/i18n'
 | 
			
		||||
import BaseTable from '@/components/base-table'
 | 
			
		||||
import { pick } from 'lodash/object'
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** 计算表格的最大高 */
 | 
			
		||||
function calcMaxHeight(num) {
 | 
			
		||||
  const FIXED_HEIGHT = 220
 | 
			
		||||
  let clientHeight = 0
 | 
			
		||||
  const bodyHeight = document.body.clientHeight || null
 | 
			
		||||
  const documentHeight = document.documentElement.clientHeight || null
 | 
			
		||||
  if (bodyHeight && documentHeight) {
 | 
			
		||||
    clientHeight = Math.max(bodyHeight, documentHeight)
 | 
			
		||||
  } else {
 | 
			
		||||
    clientHeight = documentHeight ? documentHeight : bodyHeight
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const finalHeight = clientHeight - num - FIXED_HEIGHT
 | 
			
		||||
  return finalHeight > 0 ? finalHeight : -finalHeight
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'AttrForm',
 | 
			
		||||
	components: { BaseTable },
 | 
			
		||||
	props: {
 | 
			
		||||
		isDetail: {
 | 
			
		||||
			type: Boolean,
 | 
			
		||||
			default: false
 | 
			
		||||
		},
 | 
			
		||||
		visible: {
 | 
			
		||||
			type: Boolean,
 | 
			
		||||
			default: false
 | 
			
		||||
		},
 | 
			
		||||
		/** subtable 需要设置的属性 */
 | 
			
		||||
		title: {
 | 
			
		||||
			type: String,
 | 
			
		||||
			default: ''
 | 
			
		||||
		},
 | 
			
		||||
		url: {
 | 
			
		||||
			type: String,
 | 
			
		||||
			default: ''
 | 
			
		||||
		},
 | 
			
		||||
		tableConfigs: {
 | 
			
		||||
			type: Array,
 | 
			
		||||
			default: () => []
 | 
			
		||||
		},
 | 
			
		||||
		/** 表单提交需要的属性 */
 | 
			
		||||
		relatedId: {
 | 
			
		||||
			type: String,
 | 
			
		||||
			required: true,
 | 
			
		||||
			default: null
 | 
			
		||||
		},
 | 
			
		||||
		relatedField: {
 | 
			
		||||
			type: String,
 | 
			
		||||
			required: true,
 | 
			
		||||
			default: null
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			calcMaxHeight,
 | 
			
		||||
			showAddAttr: false,
 | 
			
		||||
			dataList: [],
 | 
			
		||||
			pageIndex: 1,
 | 
			
		||||
			pageSize: 10,
 | 
			
		||||
			totalPage: 0,
 | 
			
		||||
			AttrForm: {}, // 需动态设置
 | 
			
		||||
			AttrFormRules: {} // 需动态设置
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		attrFormFields() {
 | 
			
		||||
			const _ = this.tableConfigs.filter(item => item.formField)
 | 
			
		||||
			/** 顺带配置 AttrForm */
 | 
			
		||||
			_.forEach(item => {
 | 
			
		||||
				this.$set(this.AttrForm, [item.prop], '')
 | 
			
		||||
			})
 | 
			
		||||
 | 
			
		||||
			this.$set(this.AttrForm, 'id', null)
 | 
			
		||||
			return _
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		this.getDataList()
 | 
			
		||||
		/** 设置 AttrForm 的 rules */
 | 
			
		||||
		for (const config of this.tableConfigs) {
 | 
			
		||||
			if (config.rules) {
 | 
			
		||||
				this.$set(this.AttrFormRules, [config.prop], config.rules)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		filterTableConfigs() {
 | 
			
		||||
			if (this.isDetail) {
 | 
			
		||||
				/** 如果是查看详情,就屏蔽操作列 */
 | 
			
		||||
				return this.tableConfigs.filter(opt => opt.prop !== 'operations')
 | 
			
		||||
			}
 | 
			
		||||
			return this.tableConfigs
 | 
			
		||||
		},
 | 
			
		||||
		/** init dataform */
 | 
			
		||||
		initAttrForm() {
 | 
			
		||||
			Object.entries(this.AttrForm).forEach(([key, value]) => {
 | 
			
		||||
				if (typeof value === 'object' || typeof value === 'number') {
 | 
			
		||||
					this.AttrForm[key] = null
 | 
			
		||||
				} else if (Array.isArray(value)) {
 | 
			
		||||
					this.AttrForm[key] = []
 | 
			
		||||
				} else {
 | 
			
		||||
					this.AttrForm[key] = ''
 | 
			
		||||
				}
 | 
			
		||||
			})
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		/** requests */
 | 
			
		||||
		getDataList() {
 | 
			
		||||
			this.dataListLoading = true
 | 
			
		||||
			// 获取动态属性列表
 | 
			
		||||
			this.$http({
 | 
			
		||||
				url: this.$http.adornUrl(`${this.url}/page`),
 | 
			
		||||
				method: 'get',
 | 
			
		||||
				params: this.$http.adornParams({
 | 
			
		||||
					page: this.pageIndex,
 | 
			
		||||
					limit: this.pageSize,
 | 
			
		||||
					[this.relatedField]: this.relatedId
 | 
			
		||||
					// order: 'asc/desc',
 | 
			
		||||
					// orderField: 'name'
 | 
			
		||||
				})
 | 
			
		||||
			}).then(({ data: res }) => {
 | 
			
		||||
				if (res && res.code === 0) {
 | 
			
		||||
					this.dataList = res.data.list
 | 
			
		||||
					this.totalPage = res.data.total
 | 
			
		||||
				} else {
 | 
			
		||||
					this.dataList = []
 | 
			
		||||
					this.totalPage = 0
 | 
			
		||||
				}
 | 
			
		||||
				this.dataListLoading = false
 | 
			
		||||
			})
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		/** handlers */
 | 
			
		||||
		handleOperations({ type, data: id }) {
 | 
			
		||||
			switch (type) {
 | 
			
		||||
				case 'edit':
 | 
			
		||||
					{
 | 
			
		||||
						this.showAddAttr = true
 | 
			
		||||
						this.$nextTick(() => {
 | 
			
		||||
							this.$http.get(this.$http.adornUrl(`${this.url}/${id}`)).then(({ data: res }) => {
 | 
			
		||||
								if (res && res.code === 0 && res.data) {
 | 
			
		||||
									const neededFields = [...this.attrFormFields.map(item => item.prop), 'id']
 | 
			
		||||
									const filtered = pick(res.data, neededFields)
 | 
			
		||||
									for (let field of neededFields) {
 | 
			
		||||
										this.AttrForm[field] = filtered[field]
 | 
			
		||||
									}
 | 
			
		||||
								}
 | 
			
		||||
							})
 | 
			
		||||
						})
 | 
			
		||||
					}
 | 
			
		||||
					break
 | 
			
		||||
				case 'delete':
 | 
			
		||||
					return this.deleteHandle(id)
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		deleteHandle(id) {
 | 
			
		||||
			var ids = id ? [id] : []
 | 
			
		||||
 | 
			
		||||
			this.$confirm(`${i18n.t('prompt.info', { handle: id ? i18n.t('delete').toLowerCase() : i18n.t('deleteBatch').toLowerCase() })}`, i18n.t('prompt.title'), {
 | 
			
		||||
				confirmButtonText: i18n.t('confirm'),
 | 
			
		||||
				cancelButtonText: i18n.t('cancel'),
 | 
			
		||||
				type: 'warning'
 | 
			
		||||
			}).then(() => {
 | 
			
		||||
				this.$http({
 | 
			
		||||
					url: this.$http.adornUrl(this.url),
 | 
			
		||||
					method: 'delete',
 | 
			
		||||
					data: this.$http.adornData(ids, false, 'raw')
 | 
			
		||||
				}).then(({ data }) => {
 | 
			
		||||
					if (data && data.code === 0) {
 | 
			
		||||
						this.$message({
 | 
			
		||||
							message: i18n.t('prompt.success'),
 | 
			
		||||
							type: 'success',
 | 
			
		||||
							duration: 1500,
 | 
			
		||||
							onClose: () => {
 | 
			
		||||
								this.getDataList()
 | 
			
		||||
							}
 | 
			
		||||
						})
 | 
			
		||||
					} else {
 | 
			
		||||
						this.$message.error(data.msg)
 | 
			
		||||
					}
 | 
			
		||||
				})
 | 
			
		||||
			})
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		handleCloseAttrForm() {
 | 
			
		||||
			this.showAddAttr = false
 | 
			
		||||
			this.initAttrForm()
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		handleSaveAttrForm() {
 | 
			
		||||
			this.$refs['AttrForm'].validate(valid => {
 | 
			
		||||
				if (valid) {
 | 
			
		||||
					this.$http({
 | 
			
		||||
						// url: this.$http.adornUrl(`${this.url}/${!this.AttrForm.id ? '' : this.AttrForm.id}`),
 | 
			
		||||
						url: this.$http.adornUrl(this.url),
 | 
			
		||||
						method: this.AttrForm.id ? 'put' : 'post',
 | 
			
		||||
						headers: {
 | 
			
		||||
							'Content-Type': 'application/json'
 | 
			
		||||
						},
 | 
			
		||||
						data: JSON.stringify({ ...this.AttrForm, [this.relatedField]: this.relatedId })
 | 
			
		||||
					}).then(({ data }) => {
 | 
			
		||||
						if (data && data.code === 0) {
 | 
			
		||||
							this.$message({
 | 
			
		||||
								message: i18n.t('prompt.success'),
 | 
			
		||||
								type: 'success',
 | 
			
		||||
								duration: 1500,
 | 
			
		||||
								onClose: () => {
 | 
			
		||||
									this.showAddAttr = false
 | 
			
		||||
									this.getDataList()
 | 
			
		||||
									this.initAttrForm()
 | 
			
		||||
								}
 | 
			
		||||
							})
 | 
			
		||||
						} else {
 | 
			
		||||
							this.$message.error(data.msg)
 | 
			
		||||
						}
 | 
			
		||||
					})
 | 
			
		||||
				}
 | 
			
		||||
			})
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// 每页数
 | 
			
		||||
		sizeChangeHandle(val) {
 | 
			
		||||
			this.pageSize = val
 | 
			
		||||
			this.pageIndex = 1
 | 
			
		||||
			this.getDataList()
 | 
			
		||||
		},
 | 
			
		||||
		// 当前页
 | 
			
		||||
		currentChangeHandle(val) {
 | 
			
		||||
			this.pageIndex = val
 | 
			
		||||
			this.getDataList()
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.attr-form >>> .el-form .el-form-item__label {
 | 
			
		||||
	padding: 0;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										30
									
								
								src/components/BaseAgreeOrNot.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,30 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<!-- 同意或不同意组件,点击不同意的时候出现额外的输入框说明原因 -->
 | 
			
		||||
	<el-row>
 | 
			
		||||
		<el-button type="primary" @click="doAgree">同意</el-button>
 | 
			
		||||
		<el-button @click="dontAgree">不同意</el-button>
 | 
			
		||||
	</el-row>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
	name: '',
 | 
			
		||||
	props: {},
 | 
			
		||||
	emits: ['not-agree', 'agree'],
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			reason: 'dont agree reason',
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		doAgree() {
 | 
			
		||||
			this.$emit('agree');
 | 
			
		||||
		},
 | 
			
		||||
		dontAgree() {
 | 
			
		||||
			this.$emit('not-agree', this.reason);
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
							
								
								
									
										649
									
								
								src/components/BaseDialog.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,649 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<el-dialog
 | 
			
		||||
		class="super-flexible-dialog"
 | 
			
		||||
		:title="isDetail ? title.detail : !dataForm.id ? title.add : title.edit"
 | 
			
		||||
		:visible.sync="visible"
 | 
			
		||||
		@close="handleClose"
 | 
			
		||||
		:distory-on-close="true"
 | 
			
		||||
		:close-on-click-modal="false">
 | 
			
		||||
		<div style="max-height: 60vh; overflow-y: scroll; overflow-x: hidden">
 | 
			
		||||
			<el-form ref="dataForm" :model="dataForm" :rules="dataFormRules">
 | 
			
		||||
				<!-- 如果需要更精细一点的布局,可以根据配置项实现地再复杂一点,但此处暂时全部采用一行两列布局  -->
 | 
			
		||||
				<el-row v-for="n in rows" :key="n" :gutter="20">
 | 
			
		||||
					<el-col v-for="c in COLUMN_PER_ROW" :key="`${n}+'col'+${c}`" :span="getSpan(n, c)">
 | 
			
		||||
						<!-- <el-col v-for="c in COLUMN_PER_ROW" :key="`${n}+'col'+${c}`" :span="24 / COLUMN_PER_ROW"> -->
 | 
			
		||||
						<!-- :class="{ 'hidden-input': configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].hidden }" -->
 | 
			
		||||
						<el-form-item
 | 
			
		||||
							v-if="configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)]"
 | 
			
		||||
							:prop="configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name"
 | 
			
		||||
							:key="`${n}-col-${c}-item`"
 | 
			
		||||
							:label="getLabel(n, c)">
 | 
			
		||||
							<!-- 暂时先不实现部分输入方式 -->
 | 
			
		||||
							<el-input
 | 
			
		||||
								v-if="getType(n, c) === 'input'"
 | 
			
		||||
								:placeholder="getPlaceholder(n, c)"
 | 
			
		||||
								v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]"
 | 
			
		||||
								clearable
 | 
			
		||||
								:disabled="isDetail" />
 | 
			
		||||
							<el-radio
 | 
			
		||||
								v-if="getType(n, c) === 'radio'"
 | 
			
		||||
								v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]"
 | 
			
		||||
								:disabled="isDetail" />
 | 
			
		||||
							<el-checkbox
 | 
			
		||||
								v-if="getType(n, c) === 'check'"
 | 
			
		||||
								v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]"
 | 
			
		||||
								:disabled="isDetail" />
 | 
			
		||||
							<el-select
 | 
			
		||||
								v-if="getType(n, c) === 'select'"
 | 
			
		||||
								:placeholder="getPlaceholder(n, c)"
 | 
			
		||||
								v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]"
 | 
			
		||||
								clearable
 | 
			
		||||
								:disabled="isDetail"
 | 
			
		||||
								@change="emitSelectChange(configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name, $event)">
 | 
			
		||||
								<el-option
 | 
			
		||||
									v-for="opt in configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].options"
 | 
			
		||||
									:key="opt.label + Math.random()"
 | 
			
		||||
									:label="opt.label"
 | 
			
		||||
									:value="opt.value" />
 | 
			
		||||
							</el-select>
 | 
			
		||||
							<el-switch
 | 
			
		||||
								v-if="getType(n, c) === 'switch'"
 | 
			
		||||
								v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]"
 | 
			
		||||
								:disabled="isDetail" />
 | 
			
		||||
							<el-cascader
 | 
			
		||||
								v-if="getType(n, c) === 'cascader'"
 | 
			
		||||
								v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]"
 | 
			
		||||
								:options="configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].options"
 | 
			
		||||
								:props="configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].props"
 | 
			
		||||
								:disabled="isDetail"
 | 
			
		||||
								clearable />
 | 
			
		||||
							<el-time-select
 | 
			
		||||
								v-if="getType(n, c) === 'time'"
 | 
			
		||||
								v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]"
 | 
			
		||||
								:disabled="isDetail" />
 | 
			
		||||
							<el-date-picker
 | 
			
		||||
								v-if="getType(n, c) === 'date'"
 | 
			
		||||
								v-bind="configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].props"
 | 
			
		||||
								:placeholder="getPlaceholder(n, c)"
 | 
			
		||||
								v-model="dataForm[configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)].name]"
 | 
			
		||||
								:disabled="isDetail" />
 | 
			
		||||
						</el-form-item>
 | 
			
		||||
					</el-col>
 | 
			
		||||
				</el-row>
 | 
			
		||||
 | 
			
		||||
				<!-- extra components , like Markdown or RichEdit -->
 | 
			
		||||
				<template v-if="configs.extraComponents && configs.extraComponents.length > 0">
 | 
			
		||||
					<el-form-item
 | 
			
		||||
						v-for="(ec, index) in configs.extraComponents"
 | 
			
		||||
						:key="ec.name + index"
 | 
			
		||||
						:label="ec.label"
 | 
			
		||||
						class="extra-components">
 | 
			
		||||
						<component
 | 
			
		||||
							style="margin-top: 40px"
 | 
			
		||||
							v-if="ec.hasModel"
 | 
			
		||||
							:is="ec.component"
 | 
			
		||||
							v-bind="ec.props"
 | 
			
		||||
							v-model="dataForm[ec.name]"
 | 
			
		||||
							@ready="handleEditorReady"
 | 
			
		||||
							:read-only="isDetail" />
 | 
			
		||||
						<!-- <component v-if="ec.hasModel" :is="ec.component" v-bind="ec.props" v-model="dataForm[ec.name]" /> -->
 | 
			
		||||
						<component
 | 
			
		||||
							v-else
 | 
			
		||||
							:is="ec.component"
 | 
			
		||||
							v-bind="ec.props"
 | 
			
		||||
							@uploader-update-filelist="handleUploadListUpdate($event, ec.props.extraParams.typeCode)"
 | 
			
		||||
							:uploader-inject-file-list="/*用于设备分流的*/ fileList[ec.props.extraParams.typeCode]"
 | 
			
		||||
							:read-only="isDetail" />
 | 
			
		||||
					</el-form-item>
 | 
			
		||||
				</template>
 | 
			
		||||
			</el-form>
 | 
			
		||||
 | 
			
		||||
			<!-- <template v-if="dataForm.id && configs.subtable">
 | 
			
		||||
				<attr-form :related-id="dataForm.id" v-bind="configs.subtable" :is-detail="isDetail" />
 | 
			
		||||
			</template> -->
 | 
			
		||||
		</div>
 | 
			
		||||
		<span slot="footer" class="dialog-footer">
 | 
			
		||||
			<template v-for="(operate, index) in configs.operations">
 | 
			
		||||
				<!-- {{ operate.name | btnNameFilter }} -->
 | 
			
		||||
				<el-button
 | 
			
		||||
					v-if="
 | 
			
		||||
						!isDetail &&
 | 
			
		||||
						(operate.showAlways ||
 | 
			
		||||
							(((dataForm.id && operate.showOnEdit) || (!dataForm.id && !operate.showOnEdit)) &&
 | 
			
		||||
								(operate.permission ? $hasPermission(operate.permission) : true)))
 | 
			
		||||
					"
 | 
			
		||||
					:key="`operate-${index}`"
 | 
			
		||||
					:type="btnType[operate.name]"
 | 
			
		||||
					@click="handleClick(operate)"
 | 
			
		||||
					>{{ btnName[operate.name] }}</el-button
 | 
			
		||||
				>
 | 
			
		||||
			</template>
 | 
			
		||||
			<el-button v-if="isDetail" @click="handleClick({ name: 'cancel' })">{{ $t('cancel') }}</el-button>
 | 
			
		||||
		</span>
 | 
			
		||||
	</el-dialog>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
// import CKEditor from 'ckeditor4-vue'
 | 
			
		||||
// import AttrForm from './AttrForm'
 | 
			
		||||
// import { pick } from 'lodash/object'
 | 
			
		||||
import { pick as __pick } from '@/utils/filters';
 | 
			
		||||
// import i18n from '@/i18n'
 | 
			
		||||
import $http from '@/utils/request';
 | 
			
		||||
 | 
			
		||||
const i18n = {
 | 
			
		||||
	t: (a) => a,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 标题 for i18n
 | 
			
		||||
const title = {
 | 
			
		||||
	// detail: i18n.t('detail'),
 | 
			
		||||
	// add: i18n.t('add'),
 | 
			
		||||
	// edit: i18n.t('edit'),
 | 
			
		||||
	detail: '详情',
 | 
			
		||||
	add: '添加',
 | 
			
		||||
	edit: '编辑',
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 或者也可以改造成自定义颜色:
 | 
			
		||||
const btnType = {
 | 
			
		||||
	save: 'success',
 | 
			
		||||
	update: 'primary',
 | 
			
		||||
	reset: 'text',
 | 
			
		||||
	// cancel: 'text'
 | 
			
		||||
	// add more...
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const btnName = {
 | 
			
		||||
	save: '保存',
 | 
			
		||||
	update: '更新',
 | 
			
		||||
	reset: '重置',
 | 
			
		||||
	cancel: '取消',
 | 
			
		||||
	// for i18n
 | 
			
		||||
	// save: i18n.t('save'),
 | 
			
		||||
	// update: i18n.t('update'),
 | 
			
		||||
	// reset: i18n.t('reset'),
 | 
			
		||||
	// cancel: i18n.t('cancel'),
 | 
			
		||||
	// add more...
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// 每行的列数
 | 
			
		||||
const COLUMN_PER_ROW = 2;
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'AddOrUpdateDialog',
 | 
			
		||||
	// components: { AttrForm },
 | 
			
		||||
	props: {
 | 
			
		||||
		configs: {
 | 
			
		||||
			type: Object,
 | 
			
		||||
			default: () => ({}), // 此处省去类型检查,使用者自行注意就好
 | 
			
		||||
		},
 | 
			
		||||
		url: {
 | 
			
		||||
			type: Object,
 | 
			
		||||
			default: () => ({}), // 此处省去类型检查,使用者自行注意就好
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	filters: {
 | 
			
		||||
		nameFilter: function (name) {
 | 
			
		||||
			if (!name) return null;
 | 
			
		||||
			// for i18n
 | 
			
		||||
			const defaultNames = {
 | 
			
		||||
				name: '名称',
 | 
			
		||||
				code: '编码',
 | 
			
		||||
				remark: '备注',
 | 
			
		||||
				description: '描述',
 | 
			
		||||
				specifications: '规格',
 | 
			
		||||
				// name: i18n.t('name'),
 | 
			
		||||
				// code: i18n.t('code'),
 | 
			
		||||
				// remark: i18n.t('remark'),
 | 
			
		||||
				// description: i18n.t('desc'),
 | 
			
		||||
				// specifications: i18n.t('prod.spec'),
 | 
			
		||||
				// add more...
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			return defaultNames[name];
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	// provide() {
 | 
			
		||||
	// 	return {
 | 
			
		||||
	// 		_df: this.dataForm
 | 
			
		||||
	// 	}
 | 
			
		||||
	// },
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			COLUMN_PER_ROW,
 | 
			
		||||
			title,
 | 
			
		||||
			/** 按钮相关属性 */
 | 
			
		||||
			btnName,
 | 
			
		||||
			btnType,
 | 
			
		||||
			defaultNames: {
 | 
			
		||||
				name: '名称',
 | 
			
		||||
				code: '编码',
 | 
			
		||||
				remark: '备注',
 | 
			
		||||
				description: '描述',
 | 
			
		||||
				specifications: '规格',
 | 
			
		||||
				// add more...
 | 
			
		||||
				// name: i18n.t('name'),
 | 
			
		||||
				// code: i18n.t('code'),
 | 
			
		||||
				// remark: i18n.t('remark'),
 | 
			
		||||
				// description: i18n.t('desc'),
 | 
			
		||||
				// specifications: i18n.t('prod.spec'),
 | 
			
		||||
				// add more...
 | 
			
		||||
			},
 | 
			
		||||
			defaultPlaceholders: {}, // 自动根据 defaultNames 计算得来
 | 
			
		||||
			/** 表单相关属性 */
 | 
			
		||||
			visible: false,
 | 
			
		||||
			isEdit: false,
 | 
			
		||||
			isDetail: false,
 | 
			
		||||
			dataForm: {},
 | 
			
		||||
			dataFormRules: {},
 | 
			
		||||
			tempForm: [], // 临时保存自动生成的code,或其他数据
 | 
			
		||||
			shouldWait: null,
 | 
			
		||||
			fileForm: {}, // 文件上传分流用、合并用的表单,根据 typeCode 进行分流,在请求时合并
 | 
			
		||||
			fileList: {}, // 文件加载时分流,依据 typeCode
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		rows() {
 | 
			
		||||
			// 本组件只实现了'一行两列'的表单布局
 | 
			
		||||
			return Math.ceil(this.configs.fields.length / COLUMN_PER_ROW);
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	created() {
 | 
			
		||||
		/** load lang */
 | 
			
		||||
		// CKEditor.load()
 | 
			
		||||
		// console.log('lang', CKEditor.component.props.config.defaultLanguage = 'en' )
 | 
			
		||||
	},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		/** 计算 defaultPlaceholders */
 | 
			
		||||
		// const prefix = i18n.t('hints.input');
 | 
			
		||||
		const prefix = '请输入';
 | 
			
		||||
		Object.entries(this.defaultNames).map(([key, value]) => {
 | 
			
		||||
			this.defaultPlaceholders[key] = prefix + value;
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		/** 转换 configs.fields 的结构,把纯字符串转为对象 */
 | 
			
		||||
		this.$nextTick(() => {
 | 
			
		||||
			this.configs.fields = this.configs.fields.map((item) => {
 | 
			
		||||
				if (typeof item === 'string') {
 | 
			
		||||
					return { name: item };
 | 
			
		||||
				}
 | 
			
		||||
				return item;
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			/** 动态设置dataForm字段 */
 | 
			
		||||
			this.configs.fields.forEach((item) => {
 | 
			
		||||
				this.$set(this.dataForm, [item.name], '');
 | 
			
		||||
 | 
			
		||||
				/** select 的默认值设置 */
 | 
			
		||||
				if (item.type === 'select') {
 | 
			
		||||
					const opts = item.options || [];
 | 
			
		||||
					const dft = opts.find((item) => item.default || false);
 | 
			
		||||
					if (dft) {
 | 
			
		||||
						this.$set(this.dataForm, [item.name], dft.value);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (item.api) {
 | 
			
		||||
					/** 自动请求并填充 */
 | 
			
		||||
					// or this.shouldWaitPool = []
 | 
			
		||||
					this.shouldWait =
 | 
			
		||||
						// this.$http({
 | 
			
		||||
						// 	url: this.$http.adornUrl(item.api),
 | 
			
		||||
						// 	method: 'POST', // 也可以改成动态决定
 | 
			
		||||
						// })
 | 
			
		||||
						$http
 | 
			
		||||
							.get(item.api)
 | 
			
		||||
							// .then(({ data: res }) => {
 | 
			
		||||
							.then((res) => {
 | 
			
		||||
								if (res && res.code === 0) {
 | 
			
		||||
									// this.dataForm[item.name] = res.data // <=== 此处需要对接口
 | 
			
		||||
									this.tempForm.push({ name: item.name, data: res.data });
 | 
			
		||||
								}
 | 
			
		||||
							});
 | 
			
		||||
				} // end if (item.api)
 | 
			
		||||
 | 
			
		||||
				// 如果有 relatedField,就需要在当前item的数据加载后,刷新 relatedField 的列表
 | 
			
		||||
				if (item.relatedField) {
 | 
			
		||||
					this.$watch(
 | 
			
		||||
						function () {
 | 
			
		||||
							return this.dataForm[item.name];
 | 
			
		||||
						},
 | 
			
		||||
						function (val, old) {
 | 
			
		||||
							if (val && val !== old) {
 | 
			
		||||
								this.$emit('select-change', { name: item.name, id: val });
 | 
			
		||||
							}
 | 
			
		||||
						},
 | 
			
		||||
						{ deep: true, immediate: true }
 | 
			
		||||
					);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (item.required) {
 | 
			
		||||
					const requiredRule = {
 | 
			
		||||
						required: true,
 | 
			
		||||
						message: '必填项',
 | 
			
		||||
						// message: i18n.t('validate.required'),
 | 
			
		||||
						// trigger: 'change'
 | 
			
		||||
						trigger: 'blur',
 | 
			
		||||
					};
 | 
			
		||||
					/** 检查是否已经存在该字段的规则 */
 | 
			
		||||
					const exists = this.dataFormRules[item.name] || null;
 | 
			
		||||
					/** 设置验证规则  */
 | 
			
		||||
					if (exists) {
 | 
			
		||||
						const unset = true;
 | 
			
		||||
						for (const rule of exists) {
 | 
			
		||||
							if (rule.required) unset = false;
 | 
			
		||||
						}
 | 
			
		||||
						if (unset) {
 | 
			
		||||
							exists.push(requiredRule);
 | 
			
		||||
						}
 | 
			
		||||
					} else {
 | 
			
		||||
						/** 不存在已有规则 */
 | 
			
		||||
						this.$set(this.dataFormRules, [item.name], [requiredRule]);
 | 
			
		||||
					}
 | 
			
		||||
				} // end if (item.required)
 | 
			
		||||
 | 
			
		||||
				if (item.rules) {
 | 
			
		||||
					const exists = this.dataFormRules[item.name] || null;
 | 
			
		||||
					if (exists) {
 | 
			
		||||
						// 浅拷贝过去
 | 
			
		||||
						exists.push(...item.rules);
 | 
			
		||||
					} else {
 | 
			
		||||
						this.$set(this.dataFormRules, [item.name], [...item.rules]);
 | 
			
		||||
					}
 | 
			
		||||
				} // end if (item.rules)
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			/** 计算默认值 */
 | 
			
		||||
			function calDefault(type) {
 | 
			
		||||
				switch (type) {
 | 
			
		||||
					case 'array':
 | 
			
		||||
						return [];
 | 
			
		||||
					// more case...
 | 
			
		||||
					default:
 | 
			
		||||
						return '';
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			/** 检查是否需要额外的组件 */
 | 
			
		||||
			this.configs.extraComponents &&
 | 
			
		||||
				this.configs.extraComponents.forEach((item) => {
 | 
			
		||||
					// if (Object.hasOwn(this.dataForm, [item.name])) {
 | 
			
		||||
					if (this.dataForm.hasOwnProperty(item.name)) {
 | 
			
		||||
						return;
 | 
			
		||||
					} else {
 | 
			
		||||
						this.$set(this.dataForm, [item.name], calDefault(item.fieldType));
 | 
			
		||||
					}
 | 
			
		||||
				});
 | 
			
		||||
 | 
			
		||||
			/** 单独设置 id */
 | 
			
		||||
			this.$set(this.dataForm, 'id', null);
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	methods: {
 | 
			
		||||
		getSpan(n, c) {
 | 
			
		||||
			const opt = this.configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)];
 | 
			
		||||
			return opt && opt.span ? opt.span : 24 / COLUMN_PER_ROW;
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		getLabel(n, c) {
 | 
			
		||||
			const opt = this.configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)];
 | 
			
		||||
			if (opt) {
 | 
			
		||||
				// if opt is valid
 | 
			
		||||
				return opt.label ? opt.label : this.defaultNames[opt.name];
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		getPlaceholder(n, c) {
 | 
			
		||||
			if (this.isDetail) {
 | 
			
		||||
				/** 如果是详情,就不展示 提示文本 */
 | 
			
		||||
				return '';
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			const opt = this.configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)];
 | 
			
		||||
			if (opt) {
 | 
			
		||||
				// if opt is valid
 | 
			
		||||
				return opt.placeholder
 | 
			
		||||
					? opt.placeholder
 | 
			
		||||
					: this.defaultPlaceholders[opt.name]
 | 
			
		||||
					? this.defaultPlaceholders[opt.name]
 | 
			
		||||
					: opt.label
 | 
			
		||||
					? (opt.type === 'select' ? '请选择' : '请输入') + opt.label
 | 
			
		||||
					: // ? (opt.type === 'select' ? i18n.t('choose') : i18n.t('hints.input')) + opt.label
 | 
			
		||||
					  null;
 | 
			
		||||
 | 
			
		||||
				// : opt.type === 'select'
 | 
			
		||||
				// ? i18n.t('choose')
 | 
			
		||||
				// : '请输入'
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		getType(n, c) {
 | 
			
		||||
			const opt = this.configs.fields[(n - 1) * COLUMN_PER_ROW + (c - 1)];
 | 
			
		||||
			if (opt) {
 | 
			
		||||
				if (!opt.type || ['input', 'number' /** add more.. */].includes(opt.type)) {
 | 
			
		||||
					return 'input';
 | 
			
		||||
				} else if (['select' /** add more.. */].includes(opt.type)) {
 | 
			
		||||
					return 'select';
 | 
			
		||||
				} else if (['cascader'].includes(opt.type)) {
 | 
			
		||||
					return 'cascader';
 | 
			
		||||
				} else if (['date'].includes(opt.type)) {
 | 
			
		||||
					return 'date';
 | 
			
		||||
				}
 | 
			
		||||
				// add more...
 | 
			
		||||
			} else {
 | 
			
		||||
				return 'input';
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		init(id, isdetail = false) {
 | 
			
		||||
			this.isDetail = isdetail;
 | 
			
		||||
			this.visible = true;
 | 
			
		||||
			this.$nextTick(() => {
 | 
			
		||||
				this.$refs['dataForm'].resetFields();
 | 
			
		||||
				this.dataForm.id = id || null;
 | 
			
		||||
				if (this.dataForm.id) {
 | 
			
		||||
					// this.$http({
 | 
			
		||||
					// 	url: this.$http.adornUrl(`${this.configs.infoUrl}/${this.dataForm.id}`),
 | 
			
		||||
					// 	method: 'get'
 | 
			
		||||
					// })
 | 
			
		||||
					$http.get(this.url.base + `/${this.dataForm.id}`).then((res) => {
 | 
			
		||||
						console.log('[base dialog init] ', res);
 | 
			
		||||
						if (res && res.code === 0) {
 | 
			
		||||
							const dataFormKeys = Object.keys(this.dataForm);
 | 
			
		||||
							console.log('keys ===> ', dataFormKeys);
 | 
			
		||||
							// console.log('data form keys: ', dataFormKeys, pick(res.data, dataFormKeys))
 | 
			
		||||
							this.dataForm = __pick(res.data, dataFormKeys);
 | 
			
		||||
							console.log('pick(res.data, dataFormKeys) ===> ', __pick(res.data, dataFormKeys));
 | 
			
		||||
							// LABEL: FILE_RELATED
 | 
			
		||||
							/** 对文件下载进行分流 */
 | 
			
		||||
							this.fileList = {};
 | 
			
		||||
							if (this.dataForm.files) {
 | 
			
		||||
								// console.log('files: ', this.dataForm.files)
 | 
			
		||||
								this.dataForm.files.forEach((file) => {
 | 
			
		||||
									// const fileName = file.fileUrl.split('/').pop()
 | 
			
		||||
									/** [1] 处理 fileList */
 | 
			
		||||
									// if (Object.hasOwn(this.fileList, file.typeCode)) {
 | 
			
		||||
									if (this.fileList.hasOwnProperty(file.typeCode)) {
 | 
			
		||||
										/** 已存在 */
 | 
			
		||||
										// this.fileList[file.typeCode].push({ id: file.id, name: fileName, typeCode: file.typeCode })
 | 
			
		||||
										this.fileList[file.typeCode].push(file);
 | 
			
		||||
									} else {
 | 
			
		||||
										// this.fileList[file.typeCode] = [{ id: file.id, name: fileName, typeCode: file.typeCode }]
 | 
			
		||||
										this.fileList[file.typeCode] = [file];
 | 
			
		||||
									}
 | 
			
		||||
 | 
			
		||||
									/** [2] 处理 fileForm */
 | 
			
		||||
									// if (Object.hasOwn(this.fileForm, file.typeCode)) {
 | 
			
		||||
									if (this.fileForm.hasOwnProperty(file.typeCode)) {
 | 
			
		||||
										this.fileForm[file.typeCode].push(file.id);
 | 
			
		||||
									} else {
 | 
			
		||||
										this.fileForm[file.typeCode] = [file.id];
 | 
			
		||||
									}
 | 
			
		||||
								});
 | 
			
		||||
							}
 | 
			
		||||
						}
 | 
			
		||||
					});
 | 
			
		||||
				} else {
 | 
			
		||||
					/** 如果不是编辑,就填充自动生成的数据 */
 | 
			
		||||
					if (this.shouldWait)
 | 
			
		||||
						this.shouldWait.then(() => {
 | 
			
		||||
							if (this.tempForm.length) {
 | 
			
		||||
								// console.log('create new, tempform', JSON.stringify(this.tempForm.length))
 | 
			
		||||
								this.tempForm.forEach((item) => {
 | 
			
		||||
									// console.log('item data', item.data)
 | 
			
		||||
									this.dataForm[item.name] = item.data;
 | 
			
		||||
								});
 | 
			
		||||
								// console.log('create new, dataform', JSON.stringify(this.dataForm))
 | 
			
		||||
							}
 | 
			
		||||
							this.shouldWait = null;
 | 
			
		||||
						});
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		emitSelectChange(name, id) {
 | 
			
		||||
			const currentField = this.configs.fields.find((item) => item.name === name);
 | 
			
		||||
			if (currentField.relatedField) {
 | 
			
		||||
				this.dataForm[currentField.relatedField] = null;
 | 
			
		||||
			}
 | 
			
		||||
			this.$emit('select-change', { name, id });
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		handleEditorReady(val) {},
 | 
			
		||||
 | 
			
		||||
		handleClick(btn) {
 | 
			
		||||
			/** 提取url */
 | 
			
		||||
			// const urls = {};
 | 
			
		||||
			// this.configs.operations.map((item) => {
 | 
			
		||||
			// 	urls[item.name] = {};
 | 
			
		||||
			// 	urls[item.name].url = item.url;
 | 
			
		||||
			// 	urls[item.name].extraFields = item.extraFields || {};
 | 
			
		||||
			// });
 | 
			
		||||
			/** 操作 */
 | 
			
		||||
			switch (btn.name) {
 | 
			
		||||
				case 'save':
 | 
			
		||||
				case 'update':
 | 
			
		||||
					/** 需要验证表单的操作 */
 | 
			
		||||
					this.$refs['dataForm'].validate((valid) => {
 | 
			
		||||
						if (valid) {
 | 
			
		||||
							/** 对于文件上传的单独处理(合并处理) */
 | 
			
		||||
							if (Object.keys(this.fileForm).length) {
 | 
			
		||||
								// LABEL: FILE_RELATED
 | 
			
		||||
								let fileIds = [];
 | 
			
		||||
								for (const [key, item] of Object.entries(this.fileForm)) {
 | 
			
		||||
									if (Array.isArray(item)) {
 | 
			
		||||
										fileIds = fileIds.concat(item);
 | 
			
		||||
									} else {
 | 
			
		||||
										console.error('handleClick(): 上传文件数组类型不正确');
 | 
			
		||||
									}
 | 
			
		||||
								}
 | 
			
		||||
								this.$set(this.dataForm, 'fileIds', fileIds);
 | 
			
		||||
							}
 | 
			
		||||
 | 
			
		||||
							// console.log('before send: ', this.dataForm)
 | 
			
		||||
 | 
			
		||||
							// this.$http({
 | 
			
		||||
							// 	url: this.$http.adornUrl(urls[btn.name].url),
 | 
			
		||||
							// 	method: btn.name === 'save' ? 'POST' : 'PUT',
 | 
			
		||||
							// 	data: { ...this.dataForm, ...urls[btn.name].extraFields },
 | 
			
		||||
							// })
 | 
			
		||||
							$http[btn.name === 'save' ? 'post' : 'put'](btn.url, { ...this.dataForm, ...btn.extraFields })
 | 
			
		||||
								.then((res) => {
 | 
			
		||||
									// .then(({ data: res }) => {
 | 
			
		||||
									console.log('save res: ', res, btn.name, this.dataForm);
 | 
			
		||||
									if (res && res.code === 0) {
 | 
			
		||||
										this.$message({
 | 
			
		||||
											message: '操作成功!',
 | 
			
		||||
											// message: i18n.t('prompt.success'),
 | 
			
		||||
											// message: btn.name === 'save' ? i18n.t('prompt.success') : '更新成功!',
 | 
			
		||||
											type: 'success',
 | 
			
		||||
											duration: 1500,
 | 
			
		||||
											onClose: () => {
 | 
			
		||||
												this.$emit('refreshDataList');
 | 
			
		||||
												this.visible = false;
 | 
			
		||||
											},
 | 
			
		||||
										});
 | 
			
		||||
									} else {
 | 
			
		||||
										this.$message.error(res.msg);
 | 
			
		||||
									}
 | 
			
		||||
								})
 | 
			
		||||
								.catch((err) => {
 | 
			
		||||
									this.$message({
 | 
			
		||||
										message: err,
 | 
			
		||||
										type: 'error',
 | 
			
		||||
										duration: 2000,
 | 
			
		||||
									});
 | 
			
		||||
								});
 | 
			
		||||
						}
 | 
			
		||||
					});
 | 
			
		||||
					return;
 | 
			
		||||
				case 'reset':
 | 
			
		||||
					for (const key of Object.keys(this.dataForm)) {
 | 
			
		||||
						if (typeof this.dataForm[key] === 'string') {
 | 
			
		||||
							this.dataForm[key] = '';
 | 
			
		||||
						} else if (this.dataForm[key] instanceof Array) {
 | 
			
		||||
							this.dataForm[key].splice(0);
 | 
			
		||||
						} else {
 | 
			
		||||
							this.dataForm[key] = null;
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					break;
 | 
			
		||||
				case 'cancel':
 | 
			
		||||
					this.handleClose();
 | 
			
		||||
				// add more..
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		// LABEL: FILE_RELATED
 | 
			
		||||
		handleUploadListUpdate(filelist, typeCode = 'DefaultTypeCode') {
 | 
			
		||||
			// console.log('before handleUploadListUpdate(): ', JSON.parse(JSON.stringify(this.fileForm)))
 | 
			
		||||
			// 设备类型 typeCode: EquipmentTypeFile
 | 
			
		||||
			// 设备信息 typeCode: EquipmentInfoFile | EquipmentInfoImage
 | 
			
		||||
 | 
			
		||||
			// 原先写法:直接更新 dataForm 对象,不适用于有多个上传组件的需求
 | 
			
		||||
			// this.$set(
 | 
			
		||||
			// 	this.dataForm,
 | 
			
		||||
			// 	'fileIds',
 | 
			
		||||
			// 	filelist.map(item => item.id)
 | 
			
		||||
			// )
 | 
			
		||||
			// console.log('handleUploadListUpdate(): ', this.dataForm)
 | 
			
		||||
			// 现更改为分流写法
 | 
			
		||||
			this.$set(
 | 
			
		||||
				this.fileForm,
 | 
			
		||||
				typeCode,
 | 
			
		||||
				filelist.map((item) => item.id)
 | 
			
		||||
			);
 | 
			
		||||
			// console.log('after handleUploadListUpdate(): ', this.fileForm)
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		handleClose() {
 | 
			
		||||
			this.$emit('destory-dialog');
 | 
			
		||||
			this.visible = false;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.super-flexible-dialog >>> .el-select,
 | 
			
		||||
.super-flexible-dialog >>> .el-cascader {
 | 
			
		||||
	width: 100%;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.super-flexible-dialog >>> ::-webkit-scrollbar {
 | 
			
		||||
	width: 4px;
 | 
			
		||||
	border-radius: 4px;
 | 
			
		||||
	background: #fff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.super-flexible-dialog >>> ::-webkit-scrollbar-thumb {
 | 
			
		||||
	width: 4px;
 | 
			
		||||
	border-radius: 4px;
 | 
			
		||||
	background: #ccc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.super-flexible-dialog >>> .hidden-input {
 | 
			
		||||
	display: none;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										19
									
								
								src/components/BaseDrawer.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,19 @@
 | 
			
		||||
<!-- 基本抽屉 -->
 | 
			
		||||
<template>
 | 
			
		||||
	<div></div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
	name: '',
 | 
			
		||||
	props: {},
 | 
			
		||||
	data() {
 | 
			
		||||
		return {};
 | 
			
		||||
	},
 | 
			
		||||
	created() {},
 | 
			
		||||
	mounted() {},
 | 
			
		||||
	methods: {},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
							
								
								
									
										120
									
								
								src/components/BaseListTable.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,120 @@
 | 
			
		||||
<!-- 这里单纯的配置表格就好了-->
 | 
			
		||||
<template>
 | 
			
		||||
	<div class="base-list-table w-full">
 | 
			
		||||
		<el-table :data="tableData" v-bind="tableConfig" ref="base-list-table">
 | 
			
		||||
			<!-- @cell-mouse-enter="(row, col, cell, event) => $emit('cell-mouse-enter', row, col, cell, event)"> -->
 | 
			
		||||
			<!-- @cell-mouse-leave="(row, col, cell, event) => $emit('cell-mouse-leave', row, col, cell, event)"> -->
 | 
			
		||||
			<!-- 表格头定义 -->
 | 
			
		||||
			<template v-for="(head, idx) in columnConfig">
 | 
			
		||||
				<!-- 索引列 -->
 | 
			
		||||
				<el-table-column
 | 
			
		||||
					:key="idx"
 | 
			
		||||
					v-if="head.type"
 | 
			
		||||
					:type="head.type"
 | 
			
		||||
					:label="head.label || head.name || ''"
 | 
			
		||||
					:header-align="head.align || 'center'"
 | 
			
		||||
					:align="head.align || 'center'"
 | 
			
		||||
					:width="head.width || 50"
 | 
			
		||||
					:index="
 | 
			
		||||
						head.type === 'index'
 | 
			
		||||
							? (val) => {
 | 
			
		||||
									return val + 1 + (page - 1) * size;
 | 
			
		||||
							  }
 | 
			
		||||
							: null
 | 
			
		||||
					"
 | 
			
		||||
					v-bind="head.more"></el-table-column>
 | 
			
		||||
				<!-- 普通的表头 -->
 | 
			
		||||
				<el-table-column
 | 
			
		||||
					v-else
 | 
			
		||||
					:key="idx + 'else'"
 | 
			
		||||
					:label="head.label ? head.label : head.name"
 | 
			
		||||
					:prop="head.prop || null"
 | 
			
		||||
					:width="head.width || null"
 | 
			
		||||
					:min-width="head.minWidth || null"
 | 
			
		||||
					:fixed="head.fixed || null"
 | 
			
		||||
					:show-overflow-tooltip="head.showOverflowTooltip || true"
 | 
			
		||||
					:tooltip-effect="head.tooltipEffect || 'light'"
 | 
			
		||||
					filter-placement="top"
 | 
			
		||||
					:align="head.align || null"
 | 
			
		||||
					v-bind="head.more">
 | 
			
		||||
					<!-- 子组件 -->
 | 
			
		||||
					<template v-if="head.prop" slot-scope="scope">
 | 
			
		||||
						<component
 | 
			
		||||
							v-if="head.subcomponent"
 | 
			
		||||
							:is="head.subcomponent"
 | 
			
		||||
							:key="idx + 'sub'"
 | 
			
		||||
							:inject-data="{ ...scope.row, head }"
 | 
			
		||||
							@emit-data="handleSubEmitData" />
 | 
			
		||||
						<!-- 直接展示数据或应用过滤器 -->
 | 
			
		||||
						<span v-else>{{ scope.row[head.prop] | commonFilter(head.filter) }}</span>
 | 
			
		||||
					</template>
 | 
			
		||||
 | 
			
		||||
					<!-- 多级表头 -->
 | 
			
		||||
					<template v-if="!head.prop && head.children">
 | 
			
		||||
						<TableHead
 | 
			
		||||
							v-for="(subhead, subindex) in head.children"
 | 
			
		||||
							:key="'subhead-' + idx + '-subindex-' + subindex"
 | 
			
		||||
							:opt="subhead" />
 | 
			
		||||
					</template>
 | 
			
		||||
				</el-table-column>
 | 
			
		||||
			</template>
 | 
			
		||||
		</el-table>
 | 
			
		||||
	</div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import TableHead from './TableHead.vue';
 | 
			
		||||
import $http from '@/utils/request'
 | 
			
		||||
// TODO:
 | 
			
		||||
// 1. 表格拖拽开启/关闭
 | 
			
		||||
// 2. 表格的样式'
 | 
			
		||||
// 3. more...
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'BaseListTable',
 | 
			
		||||
	components: { TableHead },
 | 
			
		||||
	filters: {
 | 
			
		||||
		commonFilter: (source, filterType = (a) => a) => {
 | 
			
		||||
			return filterType(source);
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	props: {
 | 
			
		||||
		tableConfig: {
 | 
			
		||||
			type: Object,
 | 
			
		||||
			default: () => ({}),
 | 
			
		||||
		},
 | 
			
		||||
		columnConfig: {
 | 
			
		||||
			type: Array,
 | 
			
		||||
			default: () => [],
 | 
			
		||||
		},
 | 
			
		||||
		tableData: {
 | 
			
		||||
			type: Array,
 | 
			
		||||
			default: () => [],
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	inject: ['urls'],
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			page: 1,
 | 
			
		||||
			size: 20, // 默认20
 | 
			
		||||
			dataList: []
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	watch: {
 | 
			
		||||
		// 'props.tableData': {
 | 
			
		||||
		// 	handler: () => {
 | 
			
		||||
		// 		this.$refs['base-list-table'].doLayout();
 | 
			
		||||
		// 	},
 | 
			
		||||
		// 	immediate: true,
 | 
			
		||||
		// },
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		handleSubEmitData(payload) {
 | 
			
		||||
			console.log('[component] BaseListTable handleSubEmitData(): ', payload);
 | 
			
		||||
			this.$emit('operate-event', payload);
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
							
								
								
									
										167
									
								
								src/components/BaseSearchForm.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,167 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<el-row class="base-search-form rounded">
 | 
			
		||||
		<el-form :inline="true" :model="searchForm" :rules="headConfig.rules">
 | 
			
		||||
			<!-- <el-col :span="opt.span ? +opt.span : 4" v-for="opt in options" :key="opt.id"> -->
 | 
			
		||||
			<el-form-item
 | 
			
		||||
				v-for="(opt, index) in headConfig.fields"
 | 
			
		||||
				:key="opt.prop"
 | 
			
		||||
				:label="opt.label ? opt.label : null"
 | 
			
		||||
				:prop="'' + index"
 | 
			
		||||
				:rules="opt.elconfig?.rules ? opt.elconfig.rules : undefined"
 | 
			
		||||
			>
 | 
			
		||||
				<el-input
 | 
			
		||||
					v-if="opt.input"
 | 
			
		||||
					v-model="searchForm[index]"
 | 
			
		||||
					v-bind="opt.elconfig"
 | 
			
		||||
				/>
 | 
			
		||||
				<el-select
 | 
			
		||||
					v-if="opt.select"
 | 
			
		||||
					v-model="searchForm[index]"
 | 
			
		||||
					v-bind="opt.elconfig"
 | 
			
		||||
				>
 | 
			
		||||
					<el-option
 | 
			
		||||
						v-for="item in opt.select"
 | 
			
		||||
						:key="item.value"
 | 
			
		||||
						:label="item.label"
 | 
			
		||||
						:value="item.value"
 | 
			
		||||
					/>
 | 
			
		||||
				</el-select>
 | 
			
		||||
				<el-date-picker
 | 
			
		||||
					v-if="opt.timerange"
 | 
			
		||||
					v-model="searchForm[index]"
 | 
			
		||||
					v-bind="opt.elconfig"
 | 
			
		||||
				/>
 | 
			
		||||
				<el-upload
 | 
			
		||||
					v-if="opt.upload"
 | 
			
		||||
					:key="'upload_' + Math.random().toString()"
 | 
			
		||||
					class="inline-block pl-3"
 | 
			
		||||
					action="https://jsonplaceholder.typicode.com/posts/"
 | 
			
		||||
				>
 | 
			
		||||
					<el-button type="primary">上传文件</el-button>
 | 
			
		||||
				</el-upload>
 | 
			
		||||
				<el-button
 | 
			
		||||
					v-if="opt.button && (!opt.button.permission || $hasPermission(opt.button.permission))"
 | 
			
		||||
					:key="'button' + Math.random().toString()"
 | 
			
		||||
					:type="opt.button.type"
 | 
			
		||||
					@click="handleBtnClick(opt.button.name)"
 | 
			
		||||
					>{{ opt.button.name }}</el-button
 | 
			
		||||
				>
 | 
			
		||||
			</el-form-item>
 | 
			
		||||
		</el-form>
 | 
			
		||||
	</el-row>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
	name: "",
 | 
			
		||||
	props: {
 | 
			
		||||
		headConfig: {
 | 
			
		||||
			type: Object,
 | 
			
		||||
			default: () => ({}),
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	data() {
 | 
			
		||||
		return {
 | 
			
		||||
			searchForm: {
 | 
			
		||||
				// 最大参数个数:10个,不够则在这里加
 | 
			
		||||
				0: null, // 参数一
 | 
			
		||||
				1: null,
 | 
			
		||||
				2: null,
 | 
			
		||||
				3: null,
 | 
			
		||||
				4: null,
 | 
			
		||||
				5: null,
 | 
			
		||||
				6: null,
 | 
			
		||||
				7: null,
 | 
			
		||||
				8: null,
 | 
			
		||||
				9: null,
 | 
			
		||||
			},
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	watch: {
 | 
			
		||||
		searchForm: {
 | 
			
		||||
			handler: (val) => {
 | 
			
		||||
				console.log("new val", val);
 | 
			
		||||
			},
 | 
			
		||||
			deep: true,
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	created() {},
 | 
			
		||||
	mounted() {
 | 
			
		||||
		console.log(
 | 
			
		||||
			"head form config",
 | 
			
		||||
			JSON.parse(JSON.stringify(this.headConfig))
 | 
			
		||||
		);
 | 
			
		||||
		this.headConfig.fields.forEach((field, index) => {
 | 
			
		||||
			if (field.default) {
 | 
			
		||||
				// default 必须有个 value 属性!哪怕是 input 输入框
 | 
			
		||||
				this.searchForm[index] = field.default.value;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// 更新选项列表
 | 
			
		||||
			if (!field.watch && field.fn && typeof field.fn === "function") {
 | 
			
		||||
				// 设置自身的选项列表
 | 
			
		||||
				field.fn().then((res) => {
 | 
			
		||||
					field.select = res.map((_) => {
 | 
			
		||||
						// 找到默认项
 | 
			
		||||
						if (_.default) {
 | 
			
		||||
							this.searchForm[index] = _.value;
 | 
			
		||||
						}
 | 
			
		||||
						return _;
 | 
			
		||||
					});
 | 
			
		||||
					console.log("[update] 更新选项列表", res, field.select);
 | 
			
		||||
				});
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// 模拟请求:
 | 
			
		||||
			const axios = function(url, data) {
 | 
			
		||||
				return new Promise((resolve) => {
 | 
			
		||||
					resolve("success");
 | 
			
		||||
				});
 | 
			
		||||
			};
 | 
			
		||||
 | 
			
		||||
			// 如果需要监听关联字段
 | 
			
		||||
			if (field.watch) {
 | 
			
		||||
				const { index: innerIdx, condition } = field.watch;
 | 
			
		||||
				console.log(
 | 
			
		||||
					"=====field.watch=====",
 | 
			
		||||
					innerIdx,
 | 
			
		||||
					this.searchForm[innerIdx],
 | 
			
		||||
					this.headConfig.fields[innerIdx].default
 | 
			
		||||
				);
 | 
			
		||||
				// 设置监听器
 | 
			
		||||
				this.$watch(
 | 
			
		||||
					() => this.searchForm[innerIdx],
 | 
			
		||||
					(val) => {
 | 
			
		||||
						const queryParams = { [condition]: val };
 | 
			
		||||
						// field.watch.condition.forEach(c => {
 | 
			
		||||
						// 	queryParams
 | 
			
		||||
						// })
 | 
			
		||||
						axios(field.url, queryParams).then((res) => {
 | 
			
		||||
							console.log("[==>] 更新有前置条件的字段!!!", queryParams, res);
 | 
			
		||||
							// 此处是外部的 index
 | 
			
		||||
							this.searchForm[index] = Math.floor(Math.random() * 10);
 | 
			
		||||
						});
 | 
			
		||||
					}
 | 
			
		||||
				);
 | 
			
		||||
 | 
			
		||||
				console.log("xxxxxxxxxx", this.searchForm);
 | 
			
		||||
				// 如果此时已经有默认值了,就立马根据这个默认值来发起请求
 | 
			
		||||
				if (this.searchForm[innerIdx]) {
 | 
			
		||||
					// TODO: 这个判断好像不太需要...
 | 
			
		||||
					console.log("TODO: 这个判断好像不太需要...");
 | 
			
		||||
				} else {
 | 
			
		||||
					console.log("TODO: 监听的字段还没来得及设置值呢...");
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		});
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		handleBtnClick(name) {
 | 
			
		||||
			this.$emit("btn-click", { btnName: name, payload: null });
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
							
								
								
									
										206
									
								
								src/components/BaseTable.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,206 @@
 | 
			
		||||
<!--
 | 
			
		||||
 * @Date: 2020-12-14 09:07:03
 | 
			
		||||
 * @LastEditors: gtz
 | 
			
		||||
 * @LastEditTime: 2022-06-13 08:59:21
 | 
			
		||||
 * @FilePath: \mt-bus-fe\src\components\BaseTable\index.vue
 | 
			
		||||
 * @Description:
 | 
			
		||||
-->
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="">
 | 
			
		||||
    <el-table
 | 
			
		||||
      :header-cell-style="{
 | 
			
		||||
        background: '#FAFAFA',
 | 
			
		||||
        color: '#606266',
 | 
			
		||||
        height: '40px',
 | 
			
		||||
      }"
 | 
			
		||||
      :data="renderData"
 | 
			
		||||
      :show-header="showHeader"
 | 
			
		||||
      :border="border"
 | 
			
		||||
      fit
 | 
			
		||||
      highlight-current-rows
 | 
			
		||||
      style="width: 100%"
 | 
			
		||||
      @row-click="handleRowClick"
 | 
			
		||||
      @selection-change="handleSelectionChange"
 | 
			
		||||
      >
 | 
			
		||||
      <!-- :max-height="height ? height : tableHeight(325)" -->
 | 
			
		||||
      <el-table-column v-if="sbox" type="selection" width="55" fixed />
 | 
			
		||||
      <el-table-column
 | 
			
		||||
        v-if="page && limit && !toggleCustomIndex"
 | 
			
		||||
        prop="_pageIndex"
 | 
			
		||||
        :label="'tableHeader.index' | i18nFilter"
 | 
			
		||||
        width="70"
 | 
			
		||||
        align="center"
 | 
			
		||||
        fixed
 | 
			
		||||
      />
 | 
			
		||||
      <el-table-column
 | 
			
		||||
        v-for="item in renderTableHeadList"
 | 
			
		||||
        :key="item.prop"
 | 
			
		||||
        v-bind="item"
 | 
			
		||||
        :align="item.align ? item.align : 'left'"
 | 
			
		||||
        :min-width="item.minWidth ? item.minWidth : 150"
 | 
			
		||||
        :fixed="item.isFixed ? true : false"
 | 
			
		||||
        :show-overflow-tooltip="true"
 | 
			
		||||
      >
 | 
			
		||||
        <template slot-scope="scope">
 | 
			
		||||
          <component
 | 
			
		||||
            :is="item.subcomponent"
 | 
			
		||||
            v-if="item.subcomponent"
 | 
			
		||||
            :key="scope.row.id"
 | 
			
		||||
            :inject-data="{ ...scope.row, ...item }"
 | 
			
		||||
            @emitData="emitData"
 | 
			
		||||
          />
 | 
			
		||||
          <span v-else>{{
 | 
			
		||||
            scope.row[item.prop] | commonFilter(item.filter)
 | 
			
		||||
          }}</span>
 | 
			
		||||
        </template>
 | 
			
		||||
      </el-table-column>
 | 
			
		||||
      <slot name="content" />
 | 
			
		||||
      <slot name="handleBtn" />
 | 
			
		||||
    </el-table>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
  name: "BaseTable",
 | 
			
		||||
  filters: {
 | 
			
		||||
    commonFilter: (source, filterType = (a) => a) => {
 | 
			
		||||
      return filterType(source);
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  props: {
 | 
			
		||||
    toggleCustomIndex: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      default: false,
 | 
			
		||||
    },
 | 
			
		||||
    topBtnConfig: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      default: () => {
 | 
			
		||||
        return [];
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    showHeader: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      default: true,
 | 
			
		||||
    },
 | 
			
		||||
    border: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      default: false,
 | 
			
		||||
    },
 | 
			
		||||
    height: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      required: false,
 | 
			
		||||
      default: 0,
 | 
			
		||||
    },
 | 
			
		||||
    tableData: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      required: true,
 | 
			
		||||
      // validator: (val) => val.filter((item) => !isObject(item)).length === 0,
 | 
			
		||||
    },
 | 
			
		||||
    tableConfig: {
 | 
			
		||||
      type: Array,
 | 
			
		||||
      required: true,
 | 
			
		||||
      // validator: (val) =>
 | 
			
		||||
      //   val.filter((item) => !isString(item.prop) || !isString(item.label))
 | 
			
		||||
      //     .length === 0,
 | 
			
		||||
    },
 | 
			
		||||
    isLoading: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      required: false,
 | 
			
		||||
    },
 | 
			
		||||
    page: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      required: false,
 | 
			
		||||
      default: 0,
 | 
			
		||||
    },
 | 
			
		||||
    limit: {
 | 
			
		||||
      type: Number,
 | 
			
		||||
      required: false,
 | 
			
		||||
      default: 0,
 | 
			
		||||
    },
 | 
			
		||||
    sbox: {
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      required: false,
 | 
			
		||||
    },
 | 
			
		||||
    highIndex: {
 | 
			
		||||
      // 首行是否默认高亮
 | 
			
		||||
      type: Boolean,
 | 
			
		||||
      required: false,
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      tableConfigBak: [],
 | 
			
		||||
      selectedBox: new Array(100).fill(true),
 | 
			
		||||
      // tableHeight,
 | 
			
		||||
      tableRowIndex: null,
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    renderData() {
 | 
			
		||||
      return this.tableData.map((item, index) => {
 | 
			
		||||
        return {
 | 
			
		||||
          ...item,
 | 
			
		||||
          _pageIndex: (this.page - 1) * this.limit + index + 1,
 | 
			
		||||
        };
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
    renderTableHeadList() {
 | 
			
		||||
      return this.tableConfig.filter((item, index) => {
 | 
			
		||||
        return this.selectedBox[index];
 | 
			
		||||
      });
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  watch: {
 | 
			
		||||
    tableData: function (val) {
 | 
			
		||||
      if (this.highIndex) {
 | 
			
		||||
        // 默认高亮行的,重置默认高亮行为第一行
 | 
			
		||||
        this.tableRowIndex = 0;
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  beforeMount() {
 | 
			
		||||
    this.selectedBox = new Array(100).fill(true);
 | 
			
		||||
    if (this.highIndex) {
 | 
			
		||||
      this.tableRowIndex = 0;
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  // mounted() {
 | 
			
		||||
  //   this.tableConfigBak = cloneDeep(this.tableConfig).map(item => {
 | 
			
		||||
  //     return {
 | 
			
		||||
  //       ...item,
 | 
			
		||||
  //       selected: true
 | 
			
		||||
  //     }
 | 
			
		||||
  //   })
 | 
			
		||||
  // },
 | 
			
		||||
  methods: {
 | 
			
		||||
    emitData(val) {
 | 
			
		||||
      this.$emit("emitFun", val);
 | 
			
		||||
    },
 | 
			
		||||
    clickTopButton(val) {
 | 
			
		||||
      this.$emit("clickTopBtn", val);
 | 
			
		||||
    },
 | 
			
		||||
    handleSelectionChange(val) {
 | 
			
		||||
      this.$emit("selectChangeFun", val);
 | 
			
		||||
    },
 | 
			
		||||
    handleRowClick(row) {
 | 
			
		||||
      this.tableRowIndex = this.getArrayIndex(this.tableData, row); // 获取当前点击行下标
 | 
			
		||||
      this.$emit("selectRow", row);
 | 
			
		||||
    },
 | 
			
		||||
    tableRowClassName({ row, rowIndex }) {
 | 
			
		||||
      if (rowIndex === this.tableRowIndex) {
 | 
			
		||||
        return "success-row";
 | 
			
		||||
      }
 | 
			
		||||
      return "";
 | 
			
		||||
    },
 | 
			
		||||
    getArrayIndex(arr, obj) {
 | 
			
		||||
      var i = arr.length;
 | 
			
		||||
      while (i--) {
 | 
			
		||||
        if (arr[i].id === obj.id) {
 | 
			
		||||
          return i;
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      return -1;
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										19
									
								
								src/components/BaseUpload.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,19 @@
 | 
			
		||||
<!-- 基本上传 -->
 | 
			
		||||
<template>
 | 
			
		||||
	<div></div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
	name: '',
 | 
			
		||||
	props: {},
 | 
			
		||||
	data() {
 | 
			
		||||
		return {};
 | 
			
		||||
	},
 | 
			
		||||
	created() {},
 | 
			
		||||
	mounted() {},
 | 
			
		||||
	methods: {},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
							
								
								
									
										433
									
								
								src/components/DialogWithMenu.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,433 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<el-dialog
 | 
			
		||||
		class="dialog-with-menu"
 | 
			
		||||
		:visible="selfVisible"
 | 
			
		||||
		@close="handleClose"
 | 
			
		||||
		:distory-on-close="true"
 | 
			
		||||
	>
 | 
			
		||||
		<!-- title  -->
 | 
			
		||||
		<div slot="title" class="">
 | 
			
		||||
			<h1 class="">编辑</h1>
 | 
			
		||||
		</div>
 | 
			
		||||
		<!-- menu  -->
 | 
			
		||||
		<el-tabs v-model="activeMenu" type="card" @tab-click="handleTabClick">
 | 
			
		||||
			<!-- <el-tab-pane v-for="(tab, index) in configs.menu" :key="index" :label="tab.name" :name="tab.name"> -->
 | 
			
		||||
			<el-tab-pane
 | 
			
		||||
				v-for="(tab, index) in actualMenus"
 | 
			
		||||
				:key="index"
 | 
			
		||||
				:label="tab.name"
 | 
			
		||||
				:name="tab.name"
 | 
			
		||||
			>
 | 
			
		||||
				<div v-if="index === 0">
 | 
			
		||||
					<!-- form  -->
 | 
			
		||||
					<el-form ref="dataForm" :model="dataForm">
 | 
			
		||||
						<el-row
 | 
			
		||||
							v-for="(row, rowIndex) in configs.form.rows"
 | 
			
		||||
							:key="'row_' + rowIndex"
 | 
			
		||||
							:gutter="20"
 | 
			
		||||
						>
 | 
			
		||||
							<el-col
 | 
			
		||||
								v-for="(col, colIndex) in row"
 | 
			
		||||
								:key="colIndex"
 | 
			
		||||
								:span="24 / row.length"
 | 
			
		||||
							>
 | 
			
		||||
								<el-form-item
 | 
			
		||||
									:label="col.label"
 | 
			
		||||
									:prop="col.prop"
 | 
			
		||||
									:rules="col.rules || null"
 | 
			
		||||
								>
 | 
			
		||||
									<el-input
 | 
			
		||||
										v-if="col.input"
 | 
			
		||||
										v-model="dataForm[col.prop]"
 | 
			
		||||
										clearable
 | 
			
		||||
										:disabled="detailMode"
 | 
			
		||||
										v-bind="col.elparams"
 | 
			
		||||
									/>
 | 
			
		||||
									<el-select
 | 
			
		||||
										v-if="col.select"
 | 
			
		||||
										v-model="dataForm[col.prop]"
 | 
			
		||||
										clearable
 | 
			
		||||
										:disabled="detailMode"
 | 
			
		||||
										v-bind="col.elparams"
 | 
			
		||||
										@change="handleSelectChange(col, $event)"
 | 
			
		||||
									>
 | 
			
		||||
										<el-option
 | 
			
		||||
											v-for="(opt, optIdx) in col.options"
 | 
			
		||||
											:key="'option_' + optIdx"
 | 
			
		||||
											:label="opt.label"
 | 
			
		||||
											:value="opt.value"
 | 
			
		||||
										/>
 | 
			
		||||
									</el-select>
 | 
			
		||||
									<el-switch
 | 
			
		||||
										v-if="col.switch"
 | 
			
		||||
										v-model="dataForm[col.prop]"
 | 
			
		||||
										:active-value="1"
 | 
			
		||||
										:inactive-value="0"
 | 
			
		||||
										@change="handleSwitchChange"
 | 
			
		||||
										:disabled="detailMode"
 | 
			
		||||
									/>
 | 
			
		||||
									<el-input
 | 
			
		||||
										v-if="col.textarea"
 | 
			
		||||
										type="textarea"
 | 
			
		||||
										v-model="dataForm[col.prop]"
 | 
			
		||||
										:disabled="detailMode"
 | 
			
		||||
										v-bind="col.elparams"
 | 
			
		||||
									/>
 | 
			
		||||
									<!-- add more...  -->
 | 
			
		||||
								</el-form-item>
 | 
			
		||||
							</el-col>
 | 
			
		||||
						</el-row>
 | 
			
		||||
					</el-form>
 | 
			
		||||
				</div>
 | 
			
		||||
				<div v-if="dataForm.id && index === 1">
 | 
			
		||||
					<el-button
 | 
			
		||||
						v-if="!detailMode"
 | 
			
		||||
						type="primary"
 | 
			
		||||
						style="margin-bottom: 16px"
 | 
			
		||||
						@click="handleAddParam()"
 | 
			
		||||
						>添加</el-button
 | 
			
		||||
					>
 | 
			
		||||
					<BaseListTable
 | 
			
		||||
						:table-config="null"
 | 
			
		||||
						:column-config="filteredTableProps"
 | 
			
		||||
						:table-data="subList"
 | 
			
		||||
						@operate-event="handleTableRowOperate"
 | 
			
		||||
					/>
 | 
			
		||||
					<!-- paginator  -->
 | 
			
		||||
				</div>
 | 
			
		||||
			</el-tab-pane>
 | 
			
		||||
		</el-tabs>
 | 
			
		||||
 | 
			
		||||
		<!-- sub dialog  -->
 | 
			
		||||
		<small-dialog
 | 
			
		||||
			:append-to-body="true"
 | 
			
		||||
			v-if="showSubDialog"
 | 
			
		||||
			ref="subDialog"
 | 
			
		||||
			:url="urls.subase"
 | 
			
		||||
			:configs="configs.subDialog"
 | 
			
		||||
			:related-id="dataForm.id"
 | 
			
		||||
			@refreshDataList="getSubList"
 | 
			
		||||
		></small-dialog>
 | 
			
		||||
 | 
			
		||||
		<!-- footer  -->
 | 
			
		||||
		<div slot="footer">
 | 
			
		||||
			<template v-for="(operate, index) in configs.form.operations">
 | 
			
		||||
				<el-button
 | 
			
		||||
					v-if="showButton(operate)"
 | 
			
		||||
					:key="'operation_' + index"
 | 
			
		||||
					:type="operate.type"
 | 
			
		||||
					@click="handleBtnClick(operate)"
 | 
			
		||||
					>{{ operate.label }}</el-button
 | 
			
		||||
				>
 | 
			
		||||
			</template>
 | 
			
		||||
			<el-button @click="handleBtnClick({ name: 'cancel' })">取消</el-button>
 | 
			
		||||
		</div>
 | 
			
		||||
	</el-dialog>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
import { pick as __pick } from "@/utils/filters";
 | 
			
		||||
import SmallDialog from "@/components/SmallDialog.vue";
 | 
			
		||||
import BaseListTable from "@/components/BaseListTable.vue";
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
	name: "DialogWithMenu",
 | 
			
		||||
	components: { SmallDialog, BaseListTable },
 | 
			
		||||
	props: {
 | 
			
		||||
		configs: {
 | 
			
		||||
			type: Object,
 | 
			
		||||
			default: () => ({}),
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	inject: ["urls"],
 | 
			
		||||
	data() {
 | 
			
		||||
		const dataForm = {};
 | 
			
		||||
		this.configs.form.rows.forEach((row) => {
 | 
			
		||||
			row.forEach((col) => {
 | 
			
		||||
				dataForm[col.prop] = col.default ?? "";
 | 
			
		||||
				console.log("==========>", col.prop, dataForm[col.prop]);
 | 
			
		||||
			});
 | 
			
		||||
		});
 | 
			
		||||
		return {
 | 
			
		||||
			// configs,
 | 
			
		||||
			activeMenu: this.configs.menu[0].name,
 | 
			
		||||
			dataForm,
 | 
			
		||||
			detailMode: false,
 | 
			
		||||
			selfVisible: false,
 | 
			
		||||
			showBaseDialog: false,
 | 
			
		||||
			baseDialogConfig: null,
 | 
			
		||||
			subList: [],
 | 
			
		||||
			showSubDialog: false,
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	computed: {
 | 
			
		||||
		actualMenus() {
 | 
			
		||||
			return this.configs.menu.filter((m) => {
 | 
			
		||||
				if (m.onlyEditMode && !this.dataForm.id) {
 | 
			
		||||
					return false;
 | 
			
		||||
				}
 | 
			
		||||
				return true;
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		filteredTableProps() {
 | 
			
		||||
			return this.detailMode
 | 
			
		||||
				? this.configs.table.props.filter((v) => v.prop !== "operations")
 | 
			
		||||
				: this.configs.table.props;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		/** utitilities */
 | 
			
		||||
		showButton(operate) {
 | 
			
		||||
			const notDetailMode = !this.detailMode;
 | 
			
		||||
			const showAlways = operate.showAlways ?? false;
 | 
			
		||||
			const editMode = operate.showOnEdit && this.dataForm.id;
 | 
			
		||||
			const addMode = !operate.showOnEdit && !this.dataForm.id;
 | 
			
		||||
			const permission = operate.permission
 | 
			
		||||
				? this.$hasPermission(operate.permission)
 | 
			
		||||
				: true;
 | 
			
		||||
			return (
 | 
			
		||||
				notDetailMode && (showAlways || ((editMode || addMode) && permission))
 | 
			
		||||
			);
 | 
			
		||||
		},
 | 
			
		||||
		resetForm(excludeId = false) {
 | 
			
		||||
			setTimeout(() => {
 | 
			
		||||
				Object.keys(this.dataForm).forEach((key) => {
 | 
			
		||||
					if (excludeId && key === "id") return;
 | 
			
		||||
					this.dataForm[key] = null;
 | 
			
		||||
				});
 | 
			
		||||
				this.activeMenu = this.configs.menu[0].name;
 | 
			
		||||
			}, 500);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		/** init **/
 | 
			
		||||
		init(id, detailMode) {
 | 
			
		||||
			console.log("[dialog] DialogWithHead init():", id, detailMode);
 | 
			
		||||
 | 
			
		||||
			this.detailMode = detailMode ?? false;
 | 
			
		||||
			this.$nextTick(() => {
 | 
			
		||||
				// this.$refs['dataForm'].resetFields();
 | 
			
		||||
 | 
			
		||||
				this.dataForm.id = id || null;
 | 
			
		||||
				if (this.dataForm.id) {
 | 
			
		||||
					// 如果是编辑
 | 
			
		||||
					this.$http
 | 
			
		||||
						.get(this.urls.base + `/${this.dataForm.id}`)
 | 
			
		||||
						.then(({ data: res }) => {
 | 
			
		||||
							// dev env:
 | 
			
		||||
							// if (LOCAL) res.data.id = res.data._id;
 | 
			
		||||
							// end dev env
 | 
			
		||||
							console.log("[base dialog init] ", res);
 | 
			
		||||
							if (res && res.code === 0) {
 | 
			
		||||
								const dataFormKeys = Object.keys(this.dataForm);
 | 
			
		||||
								console.log("keys ===> ", dataFormKeys);
 | 
			
		||||
								// console.log('data form keys: ', dataFormKeys, pick(res.data, dataFormKeys))
 | 
			
		||||
								this.dataForm = __pick(res.data, dataFormKeys);
 | 
			
		||||
								console.log(
 | 
			
		||||
									"pick(res.data, dataFormKeys) ===> ",
 | 
			
		||||
									__pick(res.data, dataFormKeys)
 | 
			
		||||
								);
 | 
			
		||||
								// LABEL: FILE_RELATED
 | 
			
		||||
								/** 对文件下载进行分流 */
 | 
			
		||||
								// this.fileList = {};
 | 
			
		||||
								// if (this.dataForm.files) {
 | 
			
		||||
								// 	// console.log('files: ', this.dataForm.files)
 | 
			
		||||
								// 	this.dataForm.files.forEach((file) => {
 | 
			
		||||
								// 		// const fileName = file.fileurls.split('/').pop()
 | 
			
		||||
								// 		/** [1] 处理 fileList */
 | 
			
		||||
								// 		// if (Object.hasOwn(this.fileList, file.typeCode)) {
 | 
			
		||||
								// 		if (this.fileList.hasOwnProperty(file.typeCode)) {
 | 
			
		||||
								// 			/** 已存在 */
 | 
			
		||||
								// 			// this.fileList[file.typeCode].push({ id: file.id, name: fileName, typeCode: file.typeCode })
 | 
			
		||||
								// 			this.fileList[file.typeCode].push(file);
 | 
			
		||||
								// 		} else {
 | 
			
		||||
								// 			// this.fileList[file.typeCode] = [{ id: file.id, name: fileName, typeCode: file.typeCode }]
 | 
			
		||||
								// 			this.fileList[file.typeCode] = [file];
 | 
			
		||||
								// 		}
 | 
			
		||||
 | 
			
		||||
								// 		/** [2] 处理 fileForm */
 | 
			
		||||
								// 		// if (Object.hasOwn(this.fileForm, file.typeCode)) {
 | 
			
		||||
								// 		if (this.fileForm.hasOwnProperty(file.typeCode)) {
 | 
			
		||||
								// 			this.fileForm[file.typeCode].push(file.id);
 | 
			
		||||
								// 		} else {
 | 
			
		||||
								// 			this.fileForm[file.typeCode] = [file.id];
 | 
			
		||||
								// 		}
 | 
			
		||||
								// 	});
 | 
			
		||||
								// }
 | 
			
		||||
							}
 | 
			
		||||
						});
 | 
			
		||||
				} else {
 | 
			
		||||
					// 如果不是编辑
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			this.selfVisible = true;
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		/** handlers */
 | 
			
		||||
		handleSelectChange(col, eventValue) {
 | 
			
		||||
			console.log("[dialog] select change: ", col, eventValue);
 | 
			
		||||
		},
 | 
			
		||||
		handleSwitchChange(val) {
 | 
			
		||||
			console.log("[dialog] switch change: ", val, this.dataForm);
 | 
			
		||||
		},
 | 
			
		||||
		handleBtnClick(payload) {
 | 
			
		||||
			console.log("btn click payload: ", payload);
 | 
			
		||||
 | 
			
		||||
			if ("name" in payload) {
 | 
			
		||||
				switch (payload.name) {
 | 
			
		||||
					case "cancel":
 | 
			
		||||
						this.handleClose();
 | 
			
		||||
						break;
 | 
			
		||||
					case "reset":
 | 
			
		||||
						this.resetForm(true); // true means exclude id
 | 
			
		||||
						break;
 | 
			
		||||
					case "add":
 | 
			
		||||
					case "update": {
 | 
			
		||||
						const method = payload.name === "add" ? "POST" : "PUT";
 | 
			
		||||
						this.$http({
 | 
			
		||||
							url: this.urls.base,
 | 
			
		||||
							method,
 | 
			
		||||
							data: this.dataForm,
 | 
			
		||||
						}).then(({ data: res }) => {
 | 
			
		||||
							console.log("[add&update] res is: ", res);
 | 
			
		||||
							this.$message.success(
 | 
			
		||||
								payload.name === "add" ? "添加成功" : "更新成功"
 | 
			
		||||
							);
 | 
			
		||||
							this.$emit("refreshDataList");
 | 
			
		||||
							this.handleClose();
 | 
			
		||||
						});
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				console.log("[x] 不是这么用的! 缺少name属性");
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		handleTabClick(payload) {
 | 
			
		||||
			console.log("tab click payload: ", this.activeMenu);
 | 
			
		||||
			if (this.activeMenu === this.configs.menu[1].name) {
 | 
			
		||||
				// 获取数据
 | 
			
		||||
				this.getSubList();
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		getSubList(page = 1, size = 20) {
 | 
			
		||||
			const params = {};
 | 
			
		||||
			params.page = page;
 | 
			
		||||
			params.limit = size;
 | 
			
		||||
 | 
			
		||||
			const requiredParams = this.configs.table.extraParams;
 | 
			
		||||
			if (requiredParams) {
 | 
			
		||||
				if (Array.isArray(requiredParams)) {
 | 
			
		||||
					requiredParams.forEach((str) => {
 | 
			
		||||
						if (/id/i.test(str)) {
 | 
			
		||||
							params[str] = this.dataForm.id;
 | 
			
		||||
						} else {
 | 
			
		||||
							params[str] = "";
 | 
			
		||||
						}
 | 
			
		||||
					});
 | 
			
		||||
				} else if (typeof requiredParams === "string") {
 | 
			
		||||
					// 如果需要额外参数,一般肯定需要
 | 
			
		||||
					params[this.configs.table.extraParams] = this.dataForm.id;
 | 
			
		||||
					// 此时 dataForm.id 一定是存在的
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			this.$http.get(this.urls.subpage, { params }).then(({ data: res }) => {
 | 
			
		||||
				console.log("[subList] getSubList:", res);
 | 
			
		||||
				if (res.code === 0 && res.data?.list) {
 | 
			
		||||
					// 有数据
 | 
			
		||||
					this.subList = res.data.list;
 | 
			
		||||
				} else {
 | 
			
		||||
					this.subList.splice(0);
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		handleAddParam(id) {
 | 
			
		||||
			this.showSubDialog = true;
 | 
			
		||||
			this.$nextTick(() => {
 | 
			
		||||
				this.$refs.subDialog.init(id ?? null);
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		handleClose() {
 | 
			
		||||
			this.resetForm();
 | 
			
		||||
			this.selfVisible = false;
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		/** 列表handlers */
 | 
			
		||||
		handleAddItem() {
 | 
			
		||||
			// console.log('[dialog] handleAddItem ot list...');
 | 
			
		||||
			this.showBaseDialog = true;
 | 
			
		||||
			this.$nextTick(() => {
 | 
			
		||||
				console.log("[sub-dialog] ", this.$refs["sub-dialog"].init());
 | 
			
		||||
			});
 | 
			
		||||
		},
 | 
			
		||||
		handleTableRowOperate({ type, data }) {
 | 
			
		||||
			console.log("handleTableRowOperate", type, data);
 | 
			
		||||
 | 
			
		||||
			switch (type) {
 | 
			
		||||
				case "delete": {
 | 
			
		||||
					// 确认是否删除
 | 
			
		||||
					return this.$confirm(`是否删除条目: ${data}`, "提示", {
 | 
			
		||||
						confirmButtonText: "确认",
 | 
			
		||||
						cancelButtonText: "我再想想",
 | 
			
		||||
						type: "warning",
 | 
			
		||||
					})
 | 
			
		||||
						.then(() => {
 | 
			
		||||
							// this.$http.delete(this.urls.base + `/${data}`).then((res) => {
 | 
			
		||||
							this.$http({
 | 
			
		||||
								url: this.urls.subase,
 | 
			
		||||
								method: "DELETE",
 | 
			
		||||
								data: [`${data}`],
 | 
			
		||||
							}).then(({ data: res }) => {
 | 
			
		||||
								if (res.code === 0) {
 | 
			
		||||
									this.$message.success({
 | 
			
		||||
										message: "删除成功!",
 | 
			
		||||
										duration: 1000,
 | 
			
		||||
										onClose: () => {
 | 
			
		||||
											this.getSubList(1, 20);
 | 
			
		||||
										},
 | 
			
		||||
									});
 | 
			
		||||
								}
 | 
			
		||||
							});
 | 
			
		||||
						})
 | 
			
		||||
						.catch((err) => {});
 | 
			
		||||
				}
 | 
			
		||||
				case "edit": {
 | 
			
		||||
					this.handleAddParam(data); /** data is ==> id */
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
				// case 'view-detail-action':
 | 
			
		||||
				// 	this.openDialog(data, true);
 | 
			
		||||
				// 	break;
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<style scoped>
 | 
			
		||||
.el-menu {
 | 
			
		||||
	margin: 16px 0 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.el-menu.el-menu--horizontal {
 | 
			
		||||
	border: none !important;
 | 
			
		||||
	/* background: #0f02 !important; */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* .el-menu--horizontal > .el-menu-item.is-active { */
 | 
			
		||||
/* border-bottom-color: #0b58ff; */
 | 
			
		||||
/* } */
 | 
			
		||||
 | 
			
		||||
.dialog-with-menu >>> .el-dialog__body {
 | 
			
		||||
	/* padding-top: 16px !important;
 | 
			
		||||
  padding-bottom: 16px !important; */
 | 
			
		||||
	padding-top: 0 !important;
 | 
			
		||||
	padding-bottom: 0 !important;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.el-select {
 | 
			
		||||
	width: 100% !important;
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
							
								
								
									
										2
									
								
								src/components/README.config.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,2 @@
 | 
			
		||||
配置文件选项总结
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										220
									
								
								src/components/SmallDialog.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,220 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<!-- :title="isDetail ? title.detail : !dataForm.id ? title.add : title.edit" -->
 | 
			
		||||
	<el-dialog
 | 
			
		||||
		class="a-small-dialog"
 | 
			
		||||
		:visible.sync="visible"
 | 
			
		||||
		@close="handleClose"
 | 
			
		||||
		:distory-on-close="true"
 | 
			
		||||
		:close-on-click-modal="false"
 | 
			
		||||
		v-bind="$attrs"
 | 
			
		||||
	>
 | 
			
		||||
		<!-- :append-to-body="appendToBody"> -->
 | 
			
		||||
		<div>
 | 
			
		||||
			<el-form ref="dataForm" :model="dataForm">
 | 
			
		||||
				<el-row
 | 
			
		||||
					v-for="(row, rowIndex) in configs.rows"
 | 
			
		||||
					:key="'row_' + rowIndex"
 | 
			
		||||
					:gutter="20"
 | 
			
		||||
				>
 | 
			
		||||
					<el-col
 | 
			
		||||
						v-for="(col, colIndex) in row"
 | 
			
		||||
						:key="colIndex"
 | 
			
		||||
						:span="col.span ?? 24 / row.length"
 | 
			
		||||
					>
 | 
			
		||||
						<el-form-item
 | 
			
		||||
							:prop="col.prop"
 | 
			
		||||
							:rules="col.rules || null"
 | 
			
		||||
							:label="col.label"
 | 
			
		||||
						>
 | 
			
		||||
							<el-input
 | 
			
		||||
								v-if="col.input"
 | 
			
		||||
								v-model="dataForm[col.prop]"
 | 
			
		||||
								clearable
 | 
			
		||||
								:disabled="detailMode"
 | 
			
		||||
								v-bind="col.elparams"
 | 
			
		||||
							/>
 | 
			
		||||
							<el-select
 | 
			
		||||
								v-if="col.select"
 | 
			
		||||
								v-model="dataForm[col.prop]"
 | 
			
		||||
								clearable
 | 
			
		||||
								:disabled="detailMode"
 | 
			
		||||
								v-bind="col.elparams"
 | 
			
		||||
								@change="handleSelectChange(col, $event)"
 | 
			
		||||
							>
 | 
			
		||||
								<el-option
 | 
			
		||||
									v-for="(opt, optIdx) in col.options"
 | 
			
		||||
									:key="'option_' + optIdx"
 | 
			
		||||
									:label="opt.label"
 | 
			
		||||
									:value="opt.value"
 | 
			
		||||
								/>
 | 
			
		||||
							</el-select>
 | 
			
		||||
							<el-switch
 | 
			
		||||
								v-if="col.switch"
 | 
			
		||||
								v-model="dataForm[col.prop]"
 | 
			
		||||
								:active-value="1"
 | 
			
		||||
								:inactive-value="0"
 | 
			
		||||
								@change="handleSwitchChange"
 | 
			
		||||
								:disabled="detailMode"
 | 
			
		||||
							/>
 | 
			
		||||
							<el-input
 | 
			
		||||
								v-if="col.textarea"
 | 
			
		||||
								type="textarea"
 | 
			
		||||
								v-model="dataForm[col.prop]"
 | 
			
		||||
								:disabled="detailMode"
 | 
			
		||||
								v-bind="col.elparams"
 | 
			
		||||
							/>
 | 
			
		||||
							<!-- add more...  -->
 | 
			
		||||
						</el-form-item>
 | 
			
		||||
					</el-col>
 | 
			
		||||
				</el-row>
 | 
			
		||||
			</el-form>
 | 
			
		||||
		</div>
 | 
			
		||||
 | 
			
		||||
		<!-- footer  -->
 | 
			
		||||
		<div slot="footer">
 | 
			
		||||
			<template v-for="(operate, index) in configs.operations">
 | 
			
		||||
				<el-button
 | 
			
		||||
					v-if="showButton(operate)"
 | 
			
		||||
					:key="'operation_' + index"
 | 
			
		||||
					:type="operate.type"
 | 
			
		||||
					@click="handleBtnClick(operate)"
 | 
			
		||||
					>{{ operate.label }}</el-button
 | 
			
		||||
				>
 | 
			
		||||
			</template>
 | 
			
		||||
			<el-button @click="handleBtnClick({ name: 'cancel' })">取消</el-button>
 | 
			
		||||
		</div>
 | 
			
		||||
	</el-dialog>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
// import CKEditor from 'ckeditor4-vue'
 | 
			
		||||
// import AttrForm from './AttrForm'
 | 
			
		||||
// import { pick } from 'lodash/object'
 | 
			
		||||
import { pick as __pick } from "@/utils/filters";
 | 
			
		||||
// import i18n from '@/i18n'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
	name: "SmallDialog",
 | 
			
		||||
	props: {
 | 
			
		||||
		configs: {
 | 
			
		||||
			type: Object,
 | 
			
		||||
			default: () => ({}),
 | 
			
		||||
		},
 | 
			
		||||
		relatedId: {
 | 
			
		||||
			type: String,
 | 
			
		||||
			default: "",
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
	inject: ["urls"],
 | 
			
		||||
	data() {
 | 
			
		||||
		const dataForm = {};
 | 
			
		||||
		this.configs.rows.forEach((row) => {
 | 
			
		||||
			row.forEach((col) => {
 | 
			
		||||
				dataForm[col.prop] = col.default ?? "";
 | 
			
		||||
				console.log("[small dialog]==========>", col.prop, dataForm[col.prop]);
 | 
			
		||||
			});
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		return {
 | 
			
		||||
			visible: false,
 | 
			
		||||
			detailMode: false,
 | 
			
		||||
			dataForm,
 | 
			
		||||
			dataFormRules: {},
 | 
			
		||||
			tempForm: [], // 临时保存自动生成的code,或其他数据
 | 
			
		||||
		};
 | 
			
		||||
	},
 | 
			
		||||
	methods: {
 | 
			
		||||
		/** utitilities */
 | 
			
		||||
		showButton(operate) {
 | 
			
		||||
			const notDetailMode = !this.detailMode;
 | 
			
		||||
			const showAlways = operate.showAlways ?? false;
 | 
			
		||||
			const editMode = operate.showOnEdit && this.dataForm.id;
 | 
			
		||||
			const addMode = !operate.showOnEdit && !this.dataForm.id;
 | 
			
		||||
			const permission = operate.permission
 | 
			
		||||
				? this.$hasPermission(operate.permission)
 | 
			
		||||
				: true;
 | 
			
		||||
			return (
 | 
			
		||||
				notDetailMode && (showAlways || ((editMode || addMode) && permission))
 | 
			
		||||
			);
 | 
			
		||||
		},
 | 
			
		||||
		resetForm(excludeId = false) {
 | 
			
		||||
			setTimeout(() => {
 | 
			
		||||
				Object.keys(this.dataForm).forEach((key) => {
 | 
			
		||||
					console.log(">>> clearing key: ", key);
 | 
			
		||||
					if (excludeId && key === "id") return;
 | 
			
		||||
					this.dataForm[key] = null;
 | 
			
		||||
				});
 | 
			
		||||
				this.detailMode = false;
 | 
			
		||||
			}, 500);
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		init(id, isdetail = false) {
 | 
			
		||||
			this.detailMode = isdetail;
 | 
			
		||||
			console.log("[small dialog] init", id, isdetail);
 | 
			
		||||
 | 
			
		||||
			this.$nextTick(() => {
 | 
			
		||||
				// this.$refs['dataForm'].resetFields();
 | 
			
		||||
				this.dataForm.id = id || null;
 | 
			
		||||
 | 
			
		||||
				if (this.dataForm.id) {
 | 
			
		||||
					// 如果是编辑
 | 
			
		||||
					$http.get(this.urls.subase + `/${this.dataForm.id}`).then((res) => {
 | 
			
		||||
						// dev env:
 | 
			
		||||
						if (LOCAL) res.data.id = res.data._id;
 | 
			
		||||
						// end dev env
 | 
			
		||||
						if (res && res.code === 0) {
 | 
			
		||||
							const dataFormKeys = Object.keys(this.dataForm);
 | 
			
		||||
							this.dataForm = __pick(res.data, dataFormKeys);
 | 
			
		||||
						}
 | 
			
		||||
					});
 | 
			
		||||
				} else {
 | 
			
		||||
					// 如果不是编辑
 | 
			
		||||
				}
 | 
			
		||||
			});
 | 
			
		||||
 | 
			
		||||
			this.visible = true;
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		handleSelectChange(col, event) {},
 | 
			
		||||
		handleSwitchChange() {},
 | 
			
		||||
 | 
			
		||||
		handleBtnClick(payload) {
 | 
			
		||||
			console.log("btn click payload: ", payload);
 | 
			
		||||
			console.log("configs", this.configs);
 | 
			
		||||
			if ("name" in payload) {
 | 
			
		||||
				switch (payload.name) {
 | 
			
		||||
					case "cancel":
 | 
			
		||||
						this.handleClose();
 | 
			
		||||
						break;
 | 
			
		||||
					case "add":
 | 
			
		||||
					case "update": {
 | 
			
		||||
						const method = payload.name === "add" ? "POST" : "PUT";
 | 
			
		||||
						$http({
 | 
			
		||||
							url: this.urls.subase,
 | 
			
		||||
							method,
 | 
			
		||||
							data: {
 | 
			
		||||
								...this.dataForm,
 | 
			
		||||
								[this.configs.extraParams]: this.relatedId,
 | 
			
		||||
							},
 | 
			
		||||
						}).then((res) => {
 | 
			
		||||
							console.log("[add&update] res is: ", res);
 | 
			
		||||
							this.$message.success(
 | 
			
		||||
								payload.name === "add" ? "添加成功" : "更新成功"
 | 
			
		||||
							);
 | 
			
		||||
							this.$emit("refreshDataList");
 | 
			
		||||
							this.handleClose();
 | 
			
		||||
						});
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			} else {
 | 
			
		||||
				console.log("[x] 不是这么用的! 缺少name属性");
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
 | 
			
		||||
		handleClose() {
 | 
			
		||||
			this.resetForm();
 | 
			
		||||
			this.visible = false;
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
};
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										40
									
								
								src/components/TableHead.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,40 @@
 | 
			
		||||
<template>
 | 
			
		||||
	<el-table-column
 | 
			
		||||
		:label="opt.label ? opt.label : opt.name"
 | 
			
		||||
		:prop="opt.prop || null"
 | 
			
		||||
		:width="opt.width || null"
 | 
			
		||||
		:min-width="opt.minWidth || null"
 | 
			
		||||
		:fixed="opt.fixed || null"
 | 
			
		||||
		:show-overflow-tooltip="opt.showOverflowTooltip || false"
 | 
			
		||||
		filter-placement="top"
 | 
			
		||||
		:align="opt.align || null"
 | 
			
		||||
		v-bind="opt.more"
 | 
			
		||||
	>
 | 
			
		||||
		<template v-if="opt.prop" slot-scope="scope">
 | 
			
		||||
			<component v-if="opt.subcomponent" :is="opt.subcomponent" :key="idx + 'sub'" :inject-data="{ ...scope.row, head: opt }" @emit-data="handleSubEmitData" />
 | 
			
		||||
			<!-- 直接展示数据或应用过滤器 -->
 | 
			
		||||
			<span v-else>{{ scope.row[opt.prop] | commonFilter(opt.filter) }}</span>
 | 
			
		||||
		</template>
 | 
			
		||||
		<!-- 递归 -->
 | 
			
		||||
		<template v-if="!opt.prop && opt.children">
 | 
			
		||||
			<TableHead v-for="(subhead, index) in opt.children" :key="'subhead' + index" :opt="subhead" />
 | 
			
		||||
		</template>
 | 
			
		||||
	</el-table-column>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'TableHead',
 | 
			
		||||
	filters: {
 | 
			
		||||
		commonFilter: (source, filterType = a => a) => {
 | 
			
		||||
			return filterType(source)
 | 
			
		||||
		}
 | 
			
		||||
	},
 | 
			
		||||
	props: {
 | 
			
		||||
		opt: {
 | 
			
		||||
			type: Object,
 | 
			
		||||
			default: () => ({})
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										1
									
								
								src/components/noTemplateComponents/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
用于存放没有模板的组件,一般用于表格中或弹窗里的组件插入
 | 
			
		||||
							
								
								
									
										31
									
								
								src/components/noTemplateComponents/detailComponent.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,31 @@
 | 
			
		||||
// import i18n from '@/i18n'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'TableTextComponent',
 | 
			
		||||
  props: {
 | 
			
		||||
    injectData: {
 | 
			
		||||
      type: Object,
 | 
			
		||||
      default: () => ({})
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      // for i18n inject:
 | 
			
		||||
      // defaultText: i18n.t('viewdetail')
 | 
			
		||||
      defaultText: '查看详情'
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    emitClick() {
 | 
			
		||||
      // console.log('inject data:' ,this.injectData)
 | 
			
		||||
      this.$emit('emit-data', {
 | 
			
		||||
        type: this.injectData.head?.actionName || 'view-detail-action',
 | 
			
		||||
        data: this.injectData.head?.emitFullData ? this.injectData : this.injectData.id
 | 
			
		||||
      })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  render: function (h) {
 | 
			
		||||
    // console.log('button content:', this.injectData)
 | 
			
		||||
    return h('span', null, [h('el-button', { props: { type: 'text' }, style: { paddingLeft: 0 }, on: { click: this.emitClick } }, this.injectData.head?.buttonContent || this.defaultText)])
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										98
									
								
								src/components/noTemplateComponents/operationComponent.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,98 @@
 | 
			
		||||
// import i18n from '@/i18n'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'TableOperations',
 | 
			
		||||
  props: {
 | 
			
		||||
    injectData: {
 | 
			
		||||
      type: Object,
 | 
			
		||||
      default: () => ({})
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      btnTypes: {
 | 
			
		||||
        add: 'primary',
 | 
			
		||||
        delete: 'danger',
 | 
			
		||||
        detail: 'info'
 | 
			
		||||
        // add more...
 | 
			
		||||
      },
 | 
			
		||||
      colors: {
 | 
			
		||||
        delete: '#FF5454',
 | 
			
		||||
        preview: '#f09843',
 | 
			
		||||
        design: '#99089f',
 | 
			
		||||
        // 'view-trend': 'red'
 | 
			
		||||
        // add more...
 | 
			
		||||
      },
 | 
			
		||||
      text: {
 | 
			
		||||
        // TODO: i18n
 | 
			
		||||
        // edit: i18n.t('edit'),
 | 
			
		||||
        // detail: i18n.t('detail'),
 | 
			
		||||
        // delete: i18n.t('delete'),
 | 
			
		||||
        // viewAttr: i18n.t('viewattr'),
 | 
			
		||||
        // preview: i18n.t('preview'),
 | 
			
		||||
        // design: i18n.t('design'),
 | 
			
		||||
        edit: '编辑',
 | 
			
		||||
        detail: '详情',
 | 
			
		||||
        delete: '删除',
 | 
			
		||||
        viewAttr: '查看属性',
 | 
			
		||||
        preview: '预览',
 | 
			
		||||
        design: '设计',
 | 
			
		||||
        'view-trend': '查看趋势'
 | 
			
		||||
        // add more...
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    // 发射事件
 | 
			
		||||
    emit(opt) {
 | 
			
		||||
      let emitFull = false
 | 
			
		||||
      let eventType = 'default'
 | 
			
		||||
      let customField
 | 
			
		||||
      if (typeof opt === 'object') {
 | 
			
		||||
        eventType = opt.name
 | 
			
		||||
        customField = opt.emitField || 'id'
 | 
			
		||||
        emitFull = opt.emitFull || false
 | 
			
		||||
      } else {
 | 
			
		||||
        eventType = opt
 | 
			
		||||
      }
 | 
			
		||||
      this.$emit('emit-data', { type: eventType, data: emitFull ? this.injectData : customField ? this.injectData[customField] : this.injectData.id })
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  render: function (h) {
 | 
			
		||||
    let btns = []
 | 
			
		||||
    for (const opt of this.injectData.head?.options) {
 | 
			
		||||
      const optIsObj = typeof opt === 'object'
 | 
			
		||||
 | 
			
		||||
      if (optIsObj) {
 | 
			
		||||
        // 可能需要验证权限,如 opt.permission 选项
 | 
			
		||||
        // 注意:为空字符串或null/undefined都会不验证权限
 | 
			
		||||
        if (!opt.permission || (opt.permission && this.$hasPermission(opt.permission))) {
 | 
			
		||||
          btns.push(
 | 
			
		||||
            h('el-button',
 | 
			
		||||
              {
 | 
			
		||||
                props: { type: 'text' },
 | 
			
		||||
                style: { color: this.colors[optionStr.name] || '#409EFF' },
 | 
			
		||||
                on: { click: this.emit.bind(null, opt) }
 | 
			
		||||
              },
 | 
			
		||||
              this.text[opt.name]
 | 
			
		||||
            )
 | 
			
		||||
          )
 | 
			
		||||
        }
 | 
			
		||||
      } else {
 | 
			
		||||
        // 此时 opt 是一个 string,且默认有操作权限
 | 
			
		||||
        btns.push(
 | 
			
		||||
          h('el-button',
 | 
			
		||||
            {
 | 
			
		||||
              props: { type: 'text' },
 | 
			
		||||
              style: { color: this.colors[opt] || '#409EFF' },
 | 
			
		||||
              on: { click: this.emit.bind(null, opt) }
 | 
			
		||||
            },
 | 
			
		||||
            this.text[opt]
 | 
			
		||||
          )
 | 
			
		||||
        )
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
    return h('span', null, btns)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								src/components/noTemplateComponents/richInput.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,2 @@
 | 
			
		||||
// 富文本组件
 | 
			
		||||
export default {}
 | 
			
		||||
							
								
								
									
										47
									
								
								src/components/noTemplateComponents/statusComponent.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,47 @@
 | 
			
		||||
// import i18n from '@/i18n'
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'StatusComponent',
 | 
			
		||||
  props: {
 | 
			
		||||
    injectData: {
 | 
			
		||||
      type: Object,
 | 
			
		||||
      default: () => ({})
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  data() {
 | 
			
		||||
    return {
 | 
			
		||||
      statusText: [
 | 
			
		||||
        '正常',
 | 
			
		||||
        '异常',
 | 
			
		||||
        '损坏',
 | 
			
		||||
        // more...
 | 
			
		||||
      ],
 | 
			
		||||
      statusType: [
 | 
			
		||||
        'success',
 | 
			
		||||
        'warning',
 | 
			
		||||
        'danger',
 | 
			
		||||
        // more...
 | 
			
		||||
      ]
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  computed: {
 | 
			
		||||
    isEnabled() {
 | 
			
		||||
      return this.injectData && (this.injectData.enabled === 1 || this.injectData.enabled.toString() === '1')
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  mounted() {
 | 
			
		||||
    console.log('[component] StatusComponent: ', this.injectData)
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    // 发射事件
 | 
			
		||||
    emit(opt) { }
 | 
			
		||||
  },
 | 
			
		||||
  render: function (h) {
 | 
			
		||||
    return h('el-tag',
 | 
			
		||||
      {
 | 
			
		||||
        props:
 | 
			
		||||
          { type: this.isEnabled ? this.statusType[0] : this.statusType[1] }
 | 
			
		||||
      },
 | 
			
		||||
      this.isEnabled ? this.statusText[0] : this.statusText[1])
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										2
									
								
								src/components/noTemplateComponents/switchBtn.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,2 @@
 | 
			
		||||
// 表格中的开关
 | 
			
		||||
export default {}
 | 
			
		||||
							
								
								
									
										2
									
								
								src/components/noTemplateComponents/textBtn.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,2 @@
 | 
			
		||||
// 表格中的可点击文本
 | 
			
		||||
export default {}
 | 
			
		||||
							
								
								
									
										7
									
								
								src/components/ren-dept-tree/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,7 @@
 | 
			
		||||
import RenDeptTree from './src/ren-dept-tree'
 | 
			
		||||
 | 
			
		||||
RenDeptTree.install = function (Vue) {
 | 
			
		||||
  Vue.component(RenDeptTree.name, RenDeptTree)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default RenDeptTree
 | 
			
		||||
							
								
								
									
										118
									
								
								src/components/ren-dept-tree/src/ren-dept-tree.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,118 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
  <el-input v-model="showDeptName" :placeholder="placeholder" @focus="deptDialog">
 | 
			
		||||
    <el-button slot="append" icon="el-icon-search" @click="deptDialog"></el-button>
 | 
			
		||||
  </el-input>
 | 
			
		||||
  <el-input :value="value" style="display: none"></el-input>
 | 
			
		||||
  <el-dialog :visible.sync="visibleDept" width="30%" :modal="false" :title="placeholder" :close-on-click-modal="false" :close-on-press-escape="false">
 | 
			
		||||
    <el-form size="mini" :inline="true">
 | 
			
		||||
      <el-form-item :label="$t('keyword')">
 | 
			
		||||
        <el-input v-model="filterText"></el-input>
 | 
			
		||||
      </el-form-item>
 | 
			
		||||
      <el-form-item>
 | 
			
		||||
        <el-button type="default">{{ $t('query') }}</el-button>
 | 
			
		||||
      </el-form-item>
 | 
			
		||||
    </el-form>
 | 
			
		||||
    <el-tree
 | 
			
		||||
      class="filter-tree"
 | 
			
		||||
      :data="deptList"
 | 
			
		||||
      :default-expanded-keys="expandedKeys"
 | 
			
		||||
      :props="{ label: 'name', children: 'children' }"
 | 
			
		||||
      :expand-on-click-node="false"
 | 
			
		||||
      :filter-node-method="filterNode"
 | 
			
		||||
      :highlight-current="true"
 | 
			
		||||
      node-key="id"
 | 
			
		||||
      ref="tree">
 | 
			
		||||
    </el-tree>
 | 
			
		||||
    <template slot="footer">
 | 
			
		||||
      <el-button type="default" @click="cancelHandle()" size="mini">{{ $t('cancel') }}</el-button>
 | 
			
		||||
      <el-button v-if="query" type="info" @click="clearHandle()" size="mini">{{ $t('clear') }}</el-button>
 | 
			
		||||
      <el-button type="primary" @click="commitHandle()" size="mini">{{ $t('confirm') }}</el-button>
 | 
			
		||||
    </template>
 | 
			
		||||
  </el-dialog>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
<script>
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'RenDeptTree',
 | 
			
		||||
  data () {
 | 
			
		||||
    return {
 | 
			
		||||
      filterText: '',
 | 
			
		||||
      visibleDept: false,
 | 
			
		||||
      deptList: [],
 | 
			
		||||
      showDeptName: '',
 | 
			
		||||
      expandedKeys: null,
 | 
			
		||||
      defaultProps: {
 | 
			
		||||
        children: 'children',
 | 
			
		||||
        label: 'label'
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  props: {
 | 
			
		||||
    value: [Number, String],
 | 
			
		||||
    deptName: String,
 | 
			
		||||
    query: Boolean,
 | 
			
		||||
    placeholder: String
 | 
			
		||||
  },
 | 
			
		||||
  watch: {
 | 
			
		||||
    filterText (val) {
 | 
			
		||||
      this.$refs.tree.filter(val)
 | 
			
		||||
    },
 | 
			
		||||
    deptName (val) {
 | 
			
		||||
      this.showDeptName = val
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    deptDialog () {
 | 
			
		||||
      this.expandedKeys = null
 | 
			
		||||
      if (this.$refs.tree) {
 | 
			
		||||
        this.$refs.tree.setCurrentKey(null)
 | 
			
		||||
      }
 | 
			
		||||
      this.visibleDept = true
 | 
			
		||||
      this.getDeptList(this.value)
 | 
			
		||||
    },
 | 
			
		||||
    filterNode (value, data) {
 | 
			
		||||
      if (!value) return true
 | 
			
		||||
      return data.name.indexOf(value) !== -1
 | 
			
		||||
    },
 | 
			
		||||
    getDeptList (id) {
 | 
			
		||||
      return this.$http.get('/sys/dept/list').then(({ data: res }) => {
 | 
			
		||||
        if (res.code !== 0) {
 | 
			
		||||
          return this.$message.error(res.msg)
 | 
			
		||||
        }
 | 
			
		||||
        this.deptList = res.data
 | 
			
		||||
        this.$nextTick(() => {
 | 
			
		||||
          this.$refs.tree.setCurrentKey(id)
 | 
			
		||||
          this.expandedKeys = [id]
 | 
			
		||||
        })
 | 
			
		||||
      }).catch(() => {})
 | 
			
		||||
    },
 | 
			
		||||
    cancelHandle () {
 | 
			
		||||
      this.visibleDept = false
 | 
			
		||||
      this.deptList = []
 | 
			
		||||
      this.filterText = ''
 | 
			
		||||
    },
 | 
			
		||||
    clearHandle () {
 | 
			
		||||
      this.$emit('input', '')
 | 
			
		||||
      this.$emit('update:deptName', '')
 | 
			
		||||
      this.showDeptName = ''
 | 
			
		||||
      this.visibleDept = false
 | 
			
		||||
      this.deptList = []
 | 
			
		||||
      this.filterText = ''
 | 
			
		||||
    },
 | 
			
		||||
    commitHandle () {
 | 
			
		||||
      const node = this.$refs.tree.getCurrentNode()
 | 
			
		||||
      if (!node) {
 | 
			
		||||
        this.$message.error(this.$t('dept.chooseerror'))
 | 
			
		||||
        return
 | 
			
		||||
      }
 | 
			
		||||
      this.$emit('input', node.id)
 | 
			
		||||
      this.$emit('update:deptName', node.name)
 | 
			
		||||
      this.showDeptName = node.name
 | 
			
		||||
      this.visibleDept = false
 | 
			
		||||
      this.deptList = []
 | 
			
		||||
      this.filterText = ''
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										7
									
								
								src/components/ren-radio-group/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,7 @@
 | 
			
		||||
import RenRadioGroup from './src/ren-radio-group'
 | 
			
		||||
 | 
			
		||||
RenRadioGroup.install = function (Vue) {
 | 
			
		||||
  Vue.component(RenRadioGroup.name, RenRadioGroup)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default RenRadioGroup
 | 
			
		||||
							
								
								
									
										20
									
								
								src/components/ren-radio-group/src/ren-radio-group.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,20 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <el-radio-group :value="value+''" @input="$emit('input', $event)">
 | 
			
		||||
    <el-radio :label="data.dictValue" v-for="data in dataList" :key="data.dictValue">{{data.dictLabel}}</el-radio>
 | 
			
		||||
  </el-radio-group>
 | 
			
		||||
</template>
 | 
			
		||||
<script>
 | 
			
		||||
import { getDictDataList } from '@/utils'
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'RenRadioGroup',
 | 
			
		||||
  data () {
 | 
			
		||||
    return {
 | 
			
		||||
      dataList: getDictDataList(this.dictType)
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  props: {
 | 
			
		||||
    value: [Number, String],
 | 
			
		||||
    dictType: String
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										7
									
								
								src/components/ren-region-tree/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,7 @@
 | 
			
		||||
import RenRegionTree from './src/ren-region-tree'
 | 
			
		||||
 | 
			
		||||
RenRegionTree.install = function (Vue) {
 | 
			
		||||
  Vue.component(RenRegionTree.name, RenRegionTree)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default RenRegionTree
 | 
			
		||||
							
								
								
									
										132
									
								
								src/components/ren-region-tree/src/ren-region-tree.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,132 @@
 | 
			
		||||
<template>
 | 
			
		||||
  <div class="ren-region">
 | 
			
		||||
  <el-input v-model="showName" :placeholder="placeholder" @focus="treeDialog">
 | 
			
		||||
    <el-button slot="append" icon="el-icon-search" @click="treeDialog"></el-button>
 | 
			
		||||
  </el-input>
 | 
			
		||||
  <el-input :value="value" style="display: none"></el-input>
 | 
			
		||||
  <el-dialog :visible.sync="visibleTree" width="360px" :modal="false" :title="placeholder" :close-on-click-modal="false" :close-on-press-escape="false">
 | 
			
		||||
    <el-form size="mini" :inline="true">
 | 
			
		||||
      <el-form-item :label="$t('keyword')">
 | 
			
		||||
        <el-input v-model="filterText"></el-input>
 | 
			
		||||
      </el-form-item>
 | 
			
		||||
      <el-form-item>
 | 
			
		||||
        <el-button type="default">{{ $t('query') }}</el-button>
 | 
			
		||||
      </el-form-item>
 | 
			
		||||
    </el-form>
 | 
			
		||||
    <el-tree
 | 
			
		||||
      class="filter-tree"
 | 
			
		||||
      :data="dataList"
 | 
			
		||||
      :default-expanded-keys="expandedKeys"
 | 
			
		||||
      :props="{ label: 'name', children: 'children' }"
 | 
			
		||||
      :expand-on-click-node="false"
 | 
			
		||||
      :filter-node-method="filterNode"
 | 
			
		||||
      :highlight-current="true"
 | 
			
		||||
      node-key="id"
 | 
			
		||||
      ref="tree">
 | 
			
		||||
    </el-tree>
 | 
			
		||||
    <template slot="footer">
 | 
			
		||||
      <el-button type="default" @click="cancelHandle()" size="mini">{{ $t('cancel') }}</el-button>
 | 
			
		||||
      <el-button type="info" @click="clearHandle()" size="mini">{{ $t('clear') }}</el-button>
 | 
			
		||||
      <el-button type="primary" @click="commitHandle()" size="mini">{{ $t('confirm') }}</el-button>
 | 
			
		||||
    </template>
 | 
			
		||||
  </el-dialog>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
<style lang="scss">
 | 
			
		||||
.ren-region {
 | 
			
		||||
    .filter-tree {
 | 
			
		||||
        max-height: 230px;
 | 
			
		||||
        overflow: auto;
 | 
			
		||||
    }
 | 
			
		||||
    .el-dialog__body {
 | 
			
		||||
        padding: 0px 0px 0px 20px;
 | 
			
		||||
    }
 | 
			
		||||
    .el-dialog__footer {
 | 
			
		||||
        padding: 10px 20px 8px 20px;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
</style>
 | 
			
		||||
<script>
 | 
			
		||||
import { treeDataTranslate } from '@/utils'
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'RenRegionTree',
 | 
			
		||||
  data () {
 | 
			
		||||
    return {
 | 
			
		||||
      filterText: '',
 | 
			
		||||
      visibleTree: false,
 | 
			
		||||
      dataList: [],
 | 
			
		||||
      showName: '',
 | 
			
		||||
      expandedKeys: null,
 | 
			
		||||
      defaultProps: {
 | 
			
		||||
        children: 'children',
 | 
			
		||||
        label: 'name'
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  props: {
 | 
			
		||||
    value: [Number, String],
 | 
			
		||||
    parentName: String,
 | 
			
		||||
    placeholder: String
 | 
			
		||||
  },
 | 
			
		||||
  watch: {
 | 
			
		||||
    filterText (val) {
 | 
			
		||||
      this.$refs.tree.filter(val)
 | 
			
		||||
    },
 | 
			
		||||
    parentName (val) {
 | 
			
		||||
      this.showName = val
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  methods: {
 | 
			
		||||
    treeDialog () {
 | 
			
		||||
      this.expandedKeys = null
 | 
			
		||||
      if (this.$refs.tree) {
 | 
			
		||||
        this.$refs.tree.setCurrentKey(null)
 | 
			
		||||
      }
 | 
			
		||||
      this.visibleTree = true
 | 
			
		||||
      this.getDataList(this.value)
 | 
			
		||||
    },
 | 
			
		||||
    filterNode (value, data) {
 | 
			
		||||
      if (!value) return true
 | 
			
		||||
      return data.name.indexOf(value) !== -1
 | 
			
		||||
    },
 | 
			
		||||
    getDataList (id) {
 | 
			
		||||
      return this.$http.get('/sys/region/tree').then(({ data: res }) => {
 | 
			
		||||
        if (res.code !== 0) {
 | 
			
		||||
          return this.$message.error(res.msg)
 | 
			
		||||
        }
 | 
			
		||||
        this.dataList = treeDataTranslate(res.data)
 | 
			
		||||
        this.$nextTick(() => {
 | 
			
		||||
          this.$refs.tree.setCurrentKey(id)
 | 
			
		||||
          this.expandedKeys = [id]
 | 
			
		||||
        })
 | 
			
		||||
      }).catch(() => {})
 | 
			
		||||
    },
 | 
			
		||||
    cancelHandle () {
 | 
			
		||||
      this.visibleTree = false
 | 
			
		||||
      this.dataList = []
 | 
			
		||||
      this.filterText = ''
 | 
			
		||||
    },
 | 
			
		||||
    clearHandle () {
 | 
			
		||||
      this.$emit('input', '0')
 | 
			
		||||
      this.$emit('update:parentName', '')
 | 
			
		||||
      this.showName = ''
 | 
			
		||||
      this.visibleTree = false
 | 
			
		||||
      this.dataList = []
 | 
			
		||||
      this.filterText = ''
 | 
			
		||||
    },
 | 
			
		||||
    commitHandle () {
 | 
			
		||||
      const node = this.$refs.tree.getCurrentNode()
 | 
			
		||||
      if (!node) {
 | 
			
		||||
        this.$message.error(this.$t('choose'))
 | 
			
		||||
        return
 | 
			
		||||
      }
 | 
			
		||||
      this.$emit('input', node.id)
 | 
			
		||||
      this.$emit('update:parentName', node.name)
 | 
			
		||||
      this.showName = node.name
 | 
			
		||||
      this.visibleTree = false
 | 
			
		||||
      this.dataList = []
 | 
			
		||||
      this.filterText = ''
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										7
									
								
								src/components/ren-select/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,7 @@
 | 
			
		||||
import RenSelect from './src/ren-select'
 | 
			
		||||
 | 
			
		||||
RenSelect.install = function (Vue) {
 | 
			
		||||
  Vue.component(RenSelect.name, RenSelect)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default RenSelect
 | 
			
		||||
							
								
								
									
										21
									
								
								src/components/ren-select/src/ren-select.vue
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1,21 @@
 | 
			
		||||
<template>
 | 
			
		||||
    <el-select :value="value+''" @input="$emit('input', $event)" :placeholder="placeholder" clearable>
 | 
			
		||||
        <el-option :label="data.dictLabel" v-for="data in dataList" :key="data.dictValue" :value ="data.dictValue">{{data.dictLabel}}</el-option>
 | 
			
		||||
    </el-select>
 | 
			
		||||
</template>
 | 
			
		||||
<script>
 | 
			
		||||
import { getDictDataList } from '@/utils'
 | 
			
		||||
export default {
 | 
			
		||||
  name: 'RenSelect',
 | 
			
		||||
  data () {
 | 
			
		||||
    return {
 | 
			
		||||
      dataList: getDictDataList(this.dictType)
 | 
			
		||||
    }
 | 
			
		||||
  },
 | 
			
		||||
  props: {
 | 
			
		||||
    value: [Number, String],
 | 
			
		||||
    dictType: String,
 | 
			
		||||
    placeholder: String
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
							
								
								
									
										1030
									
								
								src/element-ui/theme-variables.scss
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								src/element-ui/theme/alert.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
.el-alert{width:100%;padding:8px 16px;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;position:relative;background-color:#FFF;overflow:hidden;opacity:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:opacity .2s;transition:opacity .2s}.el-alert.is-light .el-alert__closebtn{color:#C0C4CC}.el-alert.is-dark .el-alert__closebtn,.el-alert.is-dark .el-alert__description{color:#FFF}.el-alert.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-alert--success.is-light{background-color:#f0f9eb;color:#67C23A}.el-alert--success.is-light .el-alert__description{color:#67C23A}.el-alert--success.is-dark{background-color:#67C23A;color:#FFF}.el-alert--info.is-light{background-color:#f4f4f5;color:#909399}.el-alert--info.is-dark{background-color:#909399;color:#FFF}.el-alert--info .el-alert__description{color:#909399}.el-alert--warning.is-light{background-color:#fdf6ec;color:#E6A23C}.el-alert--warning.is-light .el-alert__description{color:#E6A23C}.el-alert--warning.is-dark{background-color:#E6A23C;color:#FFF}.el-alert--error.is-light{background-color:#fef0f0;color:#F56C6C}.el-alert--error.is-light .el-alert__description{color:#F56C6C}.el-alert--error.is-dark{background-color:#F56C6C;color:#FFF}.el-alert__content{display:table-cell;padding:0 8px}.el-alert__icon{font-size:16px;width:16px}.el-alert__icon.is-big{font-size:28px;width:28px}.el-alert__title{font-size:13px;line-height:18px}.el-alert__title.is-bold{font-weight:700}.el-alert .el-alert__description{font-size:12px;margin:5px 0 0}.el-alert__closebtn{font-size:12px;opacity:1;position:absolute;top:12px;right:15px;cursor:pointer}.el-alert__closebtn.is-customed{font-style:normal;font-size:13px;top:9px}.el-alert-fade-enter,.el-alert-fade-leave-active{opacity:0}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/element-ui/theme/aside.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
.el-aside{overflow:auto;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/element-ui/theme/autocomplete.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								src/element-ui/theme/avatar.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
.el-avatar{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center;overflow:hidden;color:#fff;background:#C0C4CC;width:40px;height:40px;line-height:40px;font-size:14px}.el-avatar>img{display:block;height:100%;vertical-align:middle}.el-avatar--circle{border-radius:50%}.el-avatar--square{border-radius:4px}.el-avatar--icon{font-size:18px}.el-avatar--large{width:40px;height:40px;line-height:40px}.el-avatar--medium{width:36px;height:36px;line-height:36px}.el-avatar--small{width:28px;height:28px;line-height:28px}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/element-ui/theme/backtop.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
.el-backtop{position:fixed;background-color:#FFF;width:40px;height:40px;border-radius:50%;color:#409EFF;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;font-size:20px;-webkit-box-shadow:0 0 6px rgba(0,0,0,.12);box-shadow:0 0 6px rgba(0,0,0,.12);cursor:pointer;z-index:5}.el-backtop:hover{background-color:#F2F6FC}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/element-ui/theme/badge.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
.el-badge{position:relative;vertical-align:middle;display:inline-block}.el-badge__content{background-color:#F56C6C;border-radius:10px;color:#FFF;display:inline-block;font-size:12px;height:18px;line-height:18px;padding:0 6px;text-align:center;white-space:nowrap;border:1px solid #FFF}.el-badge__content.is-fixed{position:absolute;top:0;right:10px;-webkit-transform:translateY(-50%) translateX(100%);transform:translateY(-50%) translateX(100%)}.el-badge__content.is-fixed.is-dot{right:5px}.el-badge__content.is-dot{height:8px;width:8px;padding:0;right:0;border-radius:50%}.el-badge__content--primary{background-color:#409EFF}.el-badge__content--success{background-color:#67C23A}.el-badge__content--warning{background-color:#E6A23C}.el-badge__content--info{background-color:#909399}.el-badge__content--danger{background-color:#F56C6C}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/element-ui/theme/base.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										0
									
								
								src/element-ui/theme/breadcrumb-item.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								src/element-ui/theme/breadcrumb.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
.el-breadcrumb{font-size:14px;line-height:1}.el-breadcrumb::after,.el-breadcrumb::before{display:table;content:""}.el-breadcrumb::after{clear:both}.el-breadcrumb__separator{margin:0 9px;font-weight:700;color:#C0C4CC}.el-breadcrumb__separator[class*=icon]{margin:0 6px;font-weight:400}.el-breadcrumb__item{float:left}.el-breadcrumb__inner{color:#606266}.el-breadcrumb__inner a,.el-breadcrumb__inner.is-link{font-weight:700;text-decoration:none;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1);color:#303133}.el-breadcrumb__inner a:hover,.el-breadcrumb__inner.is-link:hover{color:#409EFF;cursor:pointer}.el-breadcrumb__item:last-child .el-breadcrumb__inner,.el-breadcrumb__item:last-child .el-breadcrumb__inner a,.el-breadcrumb__item:last-child .el-breadcrumb__inner a:hover,.el-breadcrumb__item:last-child .el-breadcrumb__inner:hover{font-weight:400;color:#606266;cursor:text}.el-breadcrumb__item:last-child .el-breadcrumb__separator{display:none}
 | 
			
		||||
							
								
								
									
										0
									
								
								src/element-ui/theme/button-group.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								src/element-ui/theme/button.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								src/element-ui/theme/calendar.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								src/element-ui/theme/card.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
.el-card{border-radius:4px;border:1px solid #EBEEF5;background-color:#FFF;overflow:hidden;color:#303133;-webkit-transition:.3s;transition:.3s}.el-card.is-always-shadow,.el-card.is-hover-shadow:focus,.el-card.is-hover-shadow:hover{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-card__header{padding:18px 20px;border-bottom:1px solid #EBEEF5;-webkit-box-sizing:border-box;box-sizing:border-box}.el-card__body{padding:20px}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/element-ui/theme/carousel-item.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
.el-carousel__item,.el-carousel__mask{position:absolute;height:100%;top:0;left:0}.el-carousel__item{width:100%;display:inline-block;overflow:hidden;z-index:0}.el-carousel__item.is-active{z-index:2}.el-carousel__item.is-animating{-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card{width:50%;-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card.is-in-stage{cursor:pointer;z-index:1}.el-carousel__item--card.is-in-stage.is-hover .el-carousel__mask,.el-carousel__item--card.is-in-stage:hover .el-carousel__mask{opacity:.12}.el-carousel__item--card.is-active{z-index:2}.el-carousel__mask{width:100%;background-color:#FFF;opacity:.24;-webkit-transition:.2s;transition:.2s}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/element-ui/theme/carousel.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
.el-carousel{position:relative}.el-carousel--horizontal{overflow-x:hidden}.el-carousel--vertical{overflow-y:hidden}.el-carousel__container{position:relative;height:300px}.el-carousel__arrow{border:none;outline:0;padding:0;margin:0;height:36px;width:36px;cursor:pointer;-webkit-transition:.3s;transition:.3s;border-radius:50%;background-color:rgba(31,45,61,.11);color:#FFF;position:absolute;top:50%;z-index:10;-webkit-transform:translateY(-50%);transform:translateY(-50%);text-align:center;font-size:12px}.el-carousel__arrow--left{left:16px}.el-carousel__arrow--right{right:16px}.el-carousel__arrow:hover{background-color:rgba(31,45,61,.23)}.el-carousel__arrow i{cursor:pointer}.el-carousel__indicators{position:absolute;list-style:none;margin:0;padding:0;z-index:2}.el-carousel__indicators--horizontal{bottom:0;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.el-carousel__indicators--vertical{right:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-carousel__indicators--outside{bottom:26px;text-align:center;position:static;-webkit-transform:none;transform:none}.el-carousel__indicators--outside .el-carousel__indicator:hover button{opacity:.64}.el-carousel__indicators--outside button{background-color:#C0C4CC;opacity:.24}.el-carousel__indicators--labels{left:0;right:0;-webkit-transform:none;transform:none;text-align:center}.el-carousel__indicators--labels .el-carousel__button{height:auto;width:auto;padding:2px 18px;font-size:12px}.el-carousel__indicators--labels .el-carousel__indicator{padding:6px 4px}.el-carousel__indicator{background-color:transparent;cursor:pointer}.el-carousel__indicator:hover button{opacity:.72}.el-carousel__indicator--horizontal{display:inline-block;padding:12px 4px}.el-carousel__indicator--vertical{padding:4px 12px}.el-carousel__indicator--vertical .el-carousel__button{width:2px;height:15px}.el-carousel__indicator.is-active button{opacity:1}.el-carousel__button{display:block;opacity:.48;width:30px;height:2px;background-color:#FFF;border:none;outline:0;padding:0;margin:0;cursor:pointer;-webkit-transition:.3s;transition:.3s}.carousel-arrow-left-enter,.carousel-arrow-left-leave-active{-webkit-transform:translateY(-50%) translateX(-10px);transform:translateY(-50%) translateX(-10px);opacity:0}.carousel-arrow-right-enter,.carousel-arrow-right-leave-active{-webkit-transform:translateY(-50%) translateX(10px);transform:translateY(-50%) translateX(10px);opacity:0}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/element-ui/theme/cascader-panel.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								src/element-ui/theme/cascader.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										0
									
								
								src/element-ui/theme/checkbox-button.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										0
									
								
								src/element-ui/theme/checkbox-group.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								src/element-ui/theme/checkbox.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								src/element-ui/theme/col.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										0
									
								
								src/element-ui/theme/collapse-item.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								src/element-ui/theme/collapse.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								src/element-ui/theme/color-picker.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								src/element-ui/theme/container.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
.el-container{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;-webkit-box-sizing:border-box;box-sizing:border-box;min-width:0}.el-container.is-vertical{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/element-ui/theme/date-picker.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								src/element-ui/theme/descriptions-item.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
.el-descriptions-item__container{display:-webkit-box;display:-ms-flexbox;display:flex}.el-descriptions-item__label.has-colon::after{content:':';position:relative;top:-.5px}.el-descriptions-item__label.is-bordered-label{font-weight:700;color:#909399;background:#fafafa}.el-descriptions-item__label:not(.is-bordered-label){margin-right:10px}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/element-ui/theme/descriptions.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
.el-descriptions-item__container{display:-webkit-box;display:-ms-flexbox;display:flex}.el-descriptions-item__label.has-colon::after{content:':';position:relative;top:-.5px}.el-descriptions-item__label.is-bordered-label{font-weight:700;color:#909399;background:#fafafa}.el-descriptions-item__label:not(.is-bordered-label){margin-right:10px}.el-descriptions{-webkit-box-sizing:border-box;box-sizing:border-box;font-size:14px;color:#303133}.el-descriptions__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-bottom:20px}.el-descriptions__title{font-size:16px;font-weight:700}.el-descriptions--mini,.el-descriptions--small{font-size:12px}.el-descriptions__body{color:#606266;background-color:#FFF}.el-descriptions__body table{border-collapse:collapse;width:100%;table-layout:fixed}.el-descriptions__body table td,.el-descriptions__body table th{-webkit-box-sizing:border-box;box-sizing:border-box;text-align:left;font-weight:400;line-height:1.5}.el-descriptions__body table td.is-left,.el-descriptions__body table th.is-left{text-align:left}.el-descriptions__body table td.is-center,.el-descriptions__body table th.is-center{text-align:center}.el-descriptions__body table td.is-right,.el-descriptions__body table th.is-right{text-align:right}.el-descriptions .is-bordered{table-layout:auto}.el-descriptions .is-bordered td,.el-descriptions .is-bordered th{border:1px solid #EBEEF5;padding:12px 10px}.el-descriptions :not(.is-bordered) td,.el-descriptions :not(.is-bordered) th{padding-bottom:12px}.el-descriptions--medium.is-bordered td,.el-descriptions--medium.is-bordered th{padding:10px}.el-descriptions--medium:not(.is-bordered) td,.el-descriptions--medium:not(.is-bordered) th{padding-bottom:10px}.el-descriptions--small.is-bordered td,.el-descriptions--small.is-bordered th{padding:8px 10px}.el-descriptions--small:not(.is-bordered) td,.el-descriptions--small:not(.is-bordered) th{padding-bottom:8px}.el-descriptions--mini.is-bordered td,.el-descriptions--mini.is-bordered th{padding:6px 10px}.el-descriptions--mini:not(.is-bordered) td,.el-descriptions--mini:not(.is-bordered) th{padding-bottom:6px}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/element-ui/theme/dialog.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
.v-modal-enter{-webkit-animation:v-modal-in .2s ease;animation:v-modal-in .2s ease}.v-modal-leave{-webkit-animation:v-modal-out .2s ease forwards;animation:v-modal-out .2s ease forwards}@-webkit-keyframes v-modal-in{0%{opacity:0}}@keyframes v-modal-in{0%{opacity:0}}@-webkit-keyframes v-modal-out{100%{opacity:0}}@keyframes v-modal-out{100%{opacity:0}}.v-modal{position:fixed;left:0;top:0;width:100%;height:100%;opacity:.5;background:#000}.el-popup-parent--hidden{overflow:hidden}.el-dialog{position:relative;margin:0 auto 50px;background:#FFF;border-radius:2px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,.3);box-shadow:0 1px 3px rgba(0,0,0,.3);-webkit-box-sizing:border-box;box-sizing:border-box;width:50%}.el-dialog.is-fullscreen{width:100%;margin-top:0;margin-bottom:0;height:100%;overflow:auto}.el-dialog__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto;margin:0}.el-dialog__header{padding:20px 20px 10px}.el-dialog__headerbtn{position:absolute;top:20px;right:20px;padding:0;background:0 0;border:none;outline:0;cursor:pointer;font-size:16px}.el-dialog__headerbtn .el-dialog__close{color:#909399}.el-dialog__headerbtn:focus .el-dialog__close,.el-dialog__headerbtn:hover .el-dialog__close{color:#409EFF}.el-dialog__title{line-height:24px;font-size:18px;color:#303133}.el-dialog__body{padding:30px 20px;color:#606266;font-size:14px;word-break:break-all}.el-dialog__footer{padding:10px 20px 20px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-dialog--center{text-align:center}.el-dialog--center .el-dialog__body{text-align:initial;padding:25px 25px 30px}.el-dialog--center .el-dialog__footer{text-align:inherit}.dialog-fade-enter-active{-webkit-animation:dialog-fade-in .3s;animation:dialog-fade-in .3s}.dialog-fade-leave-active{-webkit-animation:dialog-fade-out .3s;animation:dialog-fade-out .3s}@-webkit-keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes dialog-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes dialog-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/element-ui/theme/display.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
@media only screen and (max-width:767px){.hidden-xs-only{display:none!important}}@media only screen and (min-width:768px){.hidden-sm-and-up{display:none!important}}@media only screen and (min-width:768px) and (max-width:991px){.hidden-sm-only{display:none!important}}@media only screen and (max-width:991px){.hidden-sm-and-down{display:none!important}}@media only screen and (min-width:992px){.hidden-md-and-up{display:none!important}}@media only screen and (min-width:992px) and (max-width:1199px){.hidden-md-only{display:none!important}}@media only screen and (max-width:1199px){.hidden-md-and-down{display:none!important}}@media only screen and (min-width:1200px){.hidden-lg-and-up{display:none!important}}@media only screen and (min-width:1200px) and (max-width:1919px){.hidden-lg-only{display:none!important}}@media only screen and (max-width:1919px){.hidden-lg-and-down{display:none!important}}@media only screen and (min-width:1920px){.hidden-xl-only{display:none!important}}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/element-ui/theme/divider.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
.el-divider{background-color:#DCDFE6;position:relative}.el-divider--horizontal{display:block;height:1px;width:100%;margin:24px 0}.el-divider--vertical{display:inline-block;width:1px;height:1em;margin:0 8px;vertical-align:middle;position:relative}.el-divider__text{position:absolute;background-color:#FFF;padding:0 20px;font-weight:500;color:#303133;font-size:14px}.el-divider__text.is-left{left:20px;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-divider__text.is-center{left:50%;-webkit-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%)}.el-divider__text.is-right{right:20px;-webkit-transform:translateY(-50%);transform:translateY(-50%)}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/element-ui/theme/drawer.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										0
									
								
								src/element-ui/theme/dropdown-item.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										0
									
								
								src/element-ui/theme/dropdown-menu.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								src/element-ui/theme/dropdown.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								src/element-ui/theme/empty.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
.el-empty{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;padding:40px 0}.el-empty__image{width:160px}.el-empty__image img,.el-empty__image svg{width:100%;height:100%;vertical-align:top}.el-empty__image img{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-o-object-fit:contain;object-fit:contain}.el-empty__image svg{fill:#DCDDE0}.el-empty__description{margin-top:20px}.el-empty__description p{margin:0;font-size:14px;color:#909399}.el-empty__bottom{margin-top:20px}
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								src/element-ui/theme/fonts/element-icons.ttf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										
											BIN
										
									
								
								src/element-ui/theme/fonts/element-icons.woff
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								src/element-ui/theme/footer.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
.el-footer{padding:0 20px;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}
 | 
			
		||||
							
								
								
									
										0
									
								
								src/element-ui/theme/form-item.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								src/element-ui/theme/form.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
.el-form--inline .el-form-item,.el-form--inline .el-form-item__content{display:inline-block;vertical-align:top}.el-form-item::after,.el-form-item__content::after{clear:both}.el-form--label-left .el-form-item__label{text-align:left}.el-form--label-top .el-form-item__label{float:none;display:inline-block;text-align:left;padding:0 0 10px}.el-form--inline .el-form-item{margin-right:10px}.el-form--inline .el-form-item__label{float:none;display:inline-block}.el-form--inline.el-form--label-top .el-form-item__content{display:block}.el-form-item{margin-bottom:22px}.el-form-item::after,.el-form-item::before{display:table;content:""}.el-form-item .el-form-item{margin-bottom:0}.el-form-item--mini.el-form-item,.el-form-item--small.el-form-item{margin-bottom:18px}.el-form-item .el-input__validateIcon{display:none}.el-form-item--medium .el-form-item__content,.el-form-item--medium .el-form-item__label{line-height:36px}.el-form-item--small .el-form-item__content,.el-form-item--small .el-form-item__label{line-height:32px}.el-form-item--small .el-form-item__error{padding-top:2px}.el-form-item--mini .el-form-item__content,.el-form-item--mini .el-form-item__label{line-height:28px}.el-form-item--mini .el-form-item__error{padding-top:1px}.el-form-item__label-wrap{float:left}.el-form-item__label-wrap .el-form-item__label{display:inline-block;float:none}.el-form-item__label{text-align:right;vertical-align:middle;float:left;font-size:14px;color:#606266;line-height:40px;padding:0 12px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-form-item__content{line-height:40px;position:relative;font-size:14px}.el-form-item__content::after,.el-form-item__content::before{display:table;content:""}.el-form-item__content .el-input-group{vertical-align:top}.el-form-item__error{color:#F56C6C;font-size:12px;line-height:1;padding-top:4px;position:absolute;top:100%;left:0}.el-form-item__error--inline{position:relative;top:auto;left:auto;display:inline-block;margin-left:10px}.el-form-item.is-required:not(.is-no-asterisk) .el-form-item__label-wrap>.el-form-item__label:before,.el-form-item.is-required:not(.is-no-asterisk)>.el-form-item__label:before{content:'*';color:#F56C6C;margin-right:4px}.el-form-item.is-error .el-input__inner,.el-form-item.is-error .el-input__inner:focus,.el-form-item.is-error .el-textarea__inner,.el-form-item.is-error .el-textarea__inner:focus{border-color:#F56C6C}.el-form-item.is-error .el-input-group__append .el-input__inner,.el-form-item.is-error .el-input-group__prepend .el-input__inner{border-color:transparent}.el-form-item.is-error .el-input__validateIcon{color:#F56C6C}.el-form-item--feedback .el-input__validateIcon{display:inline-block}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/element-ui/theme/header.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
.el-header{padding:0 20px;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}
 | 
			
		||||
							
								
								
									
										1
									
								
								src/element-ui/theme/icon.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						
							
								
								
									
										1
									
								
								src/element-ui/theme/image.css
									
									
									
									
									
										Normal file
									
								
							
							
						
						@@ -0,0 +1 @@
 | 
			
		||||
.el-image__error,.el-image__placeholder{background:#F5F7FA}.el-image__error,.el-image__inner,.el-image__placeholder{width:100%;height:100%}.el-image{position:relative;display:inline-block;overflow:hidden}.el-image__inner{vertical-align:top}.el-image__inner--center{position:relative;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);display:block}.el-image__error{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;font-size:14px;color:#C0C4CC;vertical-align:middle}.el-image__preview{cursor:pointer}.el-image-viewer__wrapper{position:fixed;top:0;right:0;bottom:0;left:0}.el-image-viewer__btn{position:absolute;z-index:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;border-radius:50%;opacity:.8;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.el-image-viewer__close{top:40px;right:40px;width:40px;height:40px;font-size:24px;color:#fff;background-color:#606266}.el-image-viewer__canvas{width:100%;height:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-image-viewer__actions{left:50%;bottom:30px;-webkit-transform:translateX(-50%);transform:translateX(-50%);width:282px;height:44px;padding:0 23px;background-color:#606266;border-color:#fff;border-radius:22px}.el-image-viewer__actions__inner{width:100%;height:100%;text-align:justify;cursor:default;font-size:23px;color:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-pack:distribute;justify-content:space-around}.el-image-viewer__next,.el-image-viewer__prev{top:50%;width:44px;height:44px;font-size:24px;color:#fff;background-color:#606266;border-color:#fff}.el-image-viewer__prev{-webkit-transform:translateY(-50%);transform:translateY(-50%);left:40px}.el-image-viewer__next{-webkit-transform:translateY(-50%);transform:translateY(-50%);right:40px;text-indent:2px}.el-image-viewer__mask{position:absolute;width:100%;height:100%;top:0;left:0;opacity:.5;background:#000}.viewer-fade-enter-active{-webkit-animation:viewer-fade-in .3s;animation:viewer-fade-in .3s}.viewer-fade-leave-active{-webkit-animation:viewer-fade-out .3s;animation:viewer-fade-out .3s}@-webkit-keyframes viewer-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes viewer-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes viewer-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes viewer-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}
 | 
			
		||||