├── vue.config.js
├── public
├── favicon.ico
├── loading.gif
└── index.html
├── babel.config.js
├── src
├── sa-resources
│ ├── com-view
│ │ ├── kulian.png
│ │ ├── sa-404.vue
│ │ ├── sa-500.vue
│ │ ├── sa-403.vue
│ │ ├── sa-login.vue
│ │ └── sa-home.vue
│ ├── index
│ │ ├── admin-logo.png
│ │ ├── admin-util.js
│ │ ├── sa-index.css
│ │ ├── sa-theme.css
│ │ ├── sa-index.vue
│ │ └── sa-index.js
│ ├── sa-admin-init.js
│ └── sa-menu-list.js
├── App.vue
├── sa-view
│ ├── role
│ │ ├── mock-data.js
│ │ ├── menu-list.vue
│ │ ├── menu-setup.vue
│ │ └── role-list.vue
│ ├── case
│ │ ├── mock-joptions.js
│ │ ├── mock-data-list.js
│ │ ├── query-table-case-add.vue
│ │ ├── submit-form.vue
│ │ ├── query-table-case.vue
│ │ └── query-p-case.vue
│ ├── home
│ │ ├── mock-data-list.js
│ │ └── swiper-list.vue
│ ├── user
│ │ ├── user-add.vue
│ │ ├── user-list.vue
│ │ └── data-list.js
│ ├── article
│ │ ├── data-list.js
│ │ ├── art-add.vue
│ │ └── art-list.vue
│ └── cfg
│ │ └── system-cfg.vue
├── main.js
└── static
│ ├── sa.css
│ └── sa.js
├── .gitignore
├── package.json
├── README.md
└── LICENSE
/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | runtimeCompiler: true
3 | }
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/click33/sa-vue-admin/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/public/loading.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/click33/sa-vue-admin/HEAD/public/loading.gif
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/src/sa-resources/com-view/kulian.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/click33/sa-vue-admin/HEAD/src/sa-resources/com-view/kulian.png
--------------------------------------------------------------------------------
/src/sa-resources/index/admin-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/click33/sa-vue-admin/HEAD/src/sa-resources/index/admin-logo.png
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
16 |
17 |
20 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 |
14 | # Editor directories and files
15 | .idea
16 | .vscode
17 | *.suo
18 | *.ntvs*
19 | *.njsproj
20 | *.sln
21 | *.sw?
22 |
23 | sa-vue-admin.rar
--------------------------------------------------------------------------------
/src/sa-view/role/mock-data.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | code: 200,
3 | msg: 'ok',
4 | data: [{
5 | "id": 1,
6 | "role_name": "普通用户",
7 | "role_info": "普通用户",
8 | "is_lock": 1,
9 | "create_time": "2018-08-17T02:33:14.000+0000"
10 | }, {
11 | "id": 11,
12 | "role_name": "顶级管理员",
13 | "role_info": "最高权限",
14 | "is_lock": 1,
15 | "create_time": "2018-08-17T02:33:14.000+0000"
16 | }, {
17 | "id": 101,
18 | "role_name": "超级管理员",
19 | "role_info": "最高权限",
20 | "is_lock": 2,
21 | "create_time": "2018-08-17T03:24:01.000+0000"
22 | }]
23 | }
24 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import App from './App.vue'
3 |
4 | Vue.config.productionTip = false;
5 |
6 |
7 | // 安装 element-ui
8 | import ElementUI from 'element-ui';
9 | import 'element-ui/lib/theme-chalk/index.css';
10 | Vue.use(ElementUI);
11 |
12 | // 安装jquery与layer, (cdn方式引入的直接挂载到原型)
13 | Vue.prototype.$ = window.$;
14 | Vue.prototype.layer = window.layer;
15 |
16 | // 安装sa对象
17 | import sa from './static/sa.js';
18 | Vue.prototype.sa = sa;
19 | import './static/sa.css';
20 |
21 | // 安装sa_admin初始化方法
22 | import SaAdminInIt from './sa-resources/sa-admin-init.js';
23 | Vue.prototype.SaAdminInIt = SaAdminInIt;
24 |
25 |
26 | // 打开vue
27 | new Vue({
28 | render: h => h(App)
29 | }).$mount('#app')
30 |
--------------------------------------------------------------------------------
/src/sa-view/case/mock-joptions.js:
--------------------------------------------------------------------------------
1 | module.exports = [ // 级联选项
2 | {
3 | value: 'v1',
4 | label: '选项1',
5 | children: [
6 | {
7 | value: 'v1-1',
8 | label: '选项1-1',
9 | children: [
10 | {value: 'v1-1-1', label: '选项1-1-1'},
11 | {value: 'v1-1-2', label: '选项1-1-2'},
12 | {value: 'v1-1-3', label: '选项1-1-3'},
13 | ]
14 | },
15 | {value: 'v1-2', label: '选项1-2'},
16 | {value: 'v1-3', label: '选项1-3'},
17 | ]
18 | },
19 | {
20 | value: 'v2',
21 | label: '选项2',
22 | children: [
23 | {value: 'v2-1', label: '选项2-1'},
24 | {value: 'v2-2', label: '选项2-2'}
25 | ]
26 | },
27 | {
28 | value: 'v3',
29 | label: '选项3',
30 | children: [
31 | {value: 'v3-1', label: '选项3-1'},
32 | {value: 'v3-2', label: '选项3-2'}
33 | ]
34 | }
35 | ];
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | <%= htmlWebpackPlugin.options.title %>
10 |
11 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "sa-vue-admin",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "core-js": "^3.6.4",
12 | "element-ui": "^2.13.0",
13 | "marked": "^0.8.0",
14 | "vue": "^2.6.11",
15 | "vue-awesome-swiper": "^3.1.3",
16 | "wangeditor": "^3.1.1"
17 | },
18 | "devDependencies": {
19 | "@vue/cli-plugin-babel": "^4.2.0",
20 | "@vue/cli-plugin-eslint": "^4.2.0",
21 | "@vue/cli-service": "^4.2.0",
22 | "babel-eslint": "^10.0.3",
23 | "eslint": "^6.7.2",
24 | "eslint-plugin-vue": "^6.1.2",
25 | "vue-template-compiler": "^2.6.11"
26 | },
27 | "eslintConfig": {
28 | "root": true,
29 | "env": {
30 | "node": true,
31 | "jquery": true
32 | },
33 | "extends": [
34 | "plugin:vue/essential",
35 | "eslint:recommended"
36 | ],
37 | "parserOptions": {
38 | "parser": "babel-eslint"
39 | },
40 | "rules": {}
41 | },
42 | "browserslist": [
43 | "> 1%",
44 | "last 2 versions"
45 | ]
46 | }
47 |
--------------------------------------------------------------------------------
/src/sa-resources/com-view/sa-404.vue:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | 404 - 没有找到你想要的页面
32 |
33 |
34 |
35 |
36 |
37 |
38 |
50 |
51 |
--------------------------------------------------------------------------------
/src/sa-resources/com-view/sa-500.vue:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | 500 - 服务器好像出了点问题
32 |
33 |
34 |
35 |
36 |
37 |
38 |
50 |
51 |
--------------------------------------------------------------------------------
/src/sa-resources/com-view/sa-403.vue:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | 403 - 你还没有权限进行当前操作哦
32 |
33 |
34 |
35 |
36 |
37 |
38 |
50 |
51 |
--------------------------------------------------------------------------------
/src/sa-view/home/mock-data-list.js:
--------------------------------------------------------------------------------
1 | // 模拟数据
2 | module.exports = {
3 | code: 200,
4 | msg: 'ok',
5 | data: [{
6 | "id": 1,
7 | "title": "壁纸1",
8 | "img_src": "https://color-test.oss-cn-qingdao.aliyuncs.com/sa-admin/32.jpg",
9 | "type": 1,
10 | "link": "",
11 | "click_count": 21,
12 | "create_time": "2019-05-23T03:41:48.000+0000",
13 | "status": 1,
14 | "sort": 1,
15 | "is_update": false
16 | }, {
17 | "id": 2,
18 | "title": "壁纸2",
19 | "img_src": "https://color-test.oss-cn-qingdao.aliyuncs.com/sa-admin/46.png",
20 | "type": 1,
21 | "link": "",
22 | "click_count": 54,
23 | "create_time": "2019-05-23T03:43:15.000+0000",
24 | "status": 1,
25 | "sort": 2,
26 | "is_update": false
27 | }, {
28 | "id": 3,
29 | "title": "壁纸3",
30 | "img_src": "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2020/01/20/15795058964941214251195.jpg",
31 | "type": 1,
32 | "link": "",
33 | "click_count": 16,
34 | "create_time": "2019-05-23T03:11:16.000+0000",
35 | "status": 1,
36 | "sort": 3,
37 | "is_update": false
38 | }, {
39 | "id": 4,
40 | "title": "壁纸4",
41 | "img_src": "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2020/01/20/1579506018108368398487.png",
42 | "type": 1,
43 | "link": "",
44 | "click_count": 91,
45 | "create_time": "2019-05-23T03:11:16.000+0000",
46 | "status": 1,
47 | "sort": 3,
48 | "is_update": false
49 | }],
50 | dataCount: 1433
51 | }
52 |
--------------------------------------------------------------------------------
/src/sa-view/role/menu-list.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
10 |
11 |
菜单预览
12 |
13 |
19 |
20 | {{ s.data.name }}
21 | {{ s.data.name }} (隐藏)
22 | ———— {{s.data.info}}
23 |
24 |
25 |
26 |
27 |
28 |
29 |
52 |
--------------------------------------------------------------------------------
/src/sa-view/user/user-add.vue:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
用户添加
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | 男
30 | 女
31 |
32 |
33 |
34 |
35 | 确定
36 |
37 |
38 |
39 |
40 |
41 |
42 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/src/sa-view/case/mock-data-list.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | code: 200,
3 | msg: 'ok',
4 | data: [
5 | {
6 | id: 101,
7 | name: '苹果',
8 | icon: 'el-icon-apple',
9 | avatar: 'http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2020/01/19/15794196587511189314194.png',
10 | money: 1999,
11 | status: 1,
12 | create_time: new Date()
13 | },
14 | {
15 | id: 102,
16 | name: '香蕉',
17 | icon: 'el-icon-apple',
18 | avatar: 'http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2020/01/19/15794196587511189314194.png',
19 | money: 2555,
20 | status: 1,
21 | create_time: new Date()
22 | },
23 | {
24 | id: 103,
25 | name: '茄子',
26 | icon: 'el-icon-cherry',
27 | avatar: 'http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2020/01/19/15794196587511189314194.png',
28 | money: 4999,
29 | status: 1,
30 | create_time: new Date()
31 | },
32 | {
33 | id: 104,
34 | name: '芸豆',
35 | icon: 'el-icon-cherry',
36 | avatar: 'http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2020/01/19/15794196587511189314194.png',
37 | money: 5555,
38 | status: 1,
39 | create_time: new Date()
40 | },
41 | {
42 | id: 105,
43 | name: '木须肉',
44 | icon: 'el-icon-umbrella',
45 | avatar: 'http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2020/01/19/15794196587511189314194.png',
46 | money: 10000,
47 | status: 1,
48 | create_time: new Date()
49 | },
50 | {
51 | id: 106,
52 | name: '回锅肉',
53 | icon: 'el-icon-umbrella',
54 | avatar: 'http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2020/01/19/15794196587511189314194.png',
55 | money: 10000,
56 | status: 1,
57 | create_time: new Date()
58 | },
59 | {
60 | id: 107,
61 | name: '辣子鸡',
62 | icon: 'el-icon-user',
63 | avatar: 'http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2020/01/19/15794196587511189314194.png',
64 | money: 99999,
65 | status: 2,
66 | create_time: new Date()
67 | },
68 | {
69 | id: 108,
70 | name: '大萝贝',
71 | icon: 'el-icon-user',
72 | avatar: 'http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2020/01/19/15794196587511189314194.png',
73 | money: 23333,
74 | status: 2,
75 | create_time: new Date()
76 | },
77 | ],
78 | dataCount: 1244
79 | }
--------------------------------------------------------------------------------
/src/sa-view/article/data-list.js:
--------------------------------------------------------------------------------
1 | // 模拟数据
2 | module.exports = {
3 | code: 200,
4 | msg: 'ok',
5 | data: [{
6 | "id": 20,
7 | "title": "那个清晨",
8 | "content": "那个清晨一大早,便被母亲叫起。我有些不满,平常我是总要在床上多赖一会儿的。可当我迷迷糊糊的看到母亲紧绷的脸庞时...",
9 | "see_count": 356,
10 | "like_count": 55,
11 | "share_count": 13,
12 | "create_username": '省长',
13 | "is_public": 1,
14 | "create_time": "2019-05-12"
15 | },
16 | {
17 | "id": 17,
18 | "title": "人生,就是一场抵达",
19 | "content": "庄子说,人生天地之间,若白驹过隙,忽然而已。人生就是一场抵达,我们总以为来日方长...",
20 | "see_count": 200,
21 | "like_count": 12,
22 | "share_count": 6,
23 | "create_username": '小言',
24 | "is_public": 1,
25 | "create_time": "2019-05-12"
26 | },
27 | {
28 | "id": 11,
29 | "title": "气质女生与世界先生",
30 | "content": "我把衣柜翻了个底朝天,花花绿绿地堆了满床。谢雨帆盘腿坐在电脑前打游戏,嗑着瓜子眼皮也不抬一下,半晌才悠悠地吐出一句...",
31 | "see_count": 240,
32 | "like_count": 22,
33 | "share_count": 15,
34 | "create_username": 'fan哈',
35 | "is_public": 2,
36 | "create_time": "2019-05-10"
37 | },
38 | {
39 | "id": 9,
40 | "title": "善待朋友,珍惜拥有",
41 | "content": "不要弄丢,一个对你好的人;不要漠视,一份待你深的情。不是谁都能包容你的臭脾气,更不是谁都能一直等下去...",
42 | "see_count": 2420,
43 | "like_count": 122,
44 | "share_count": 95,
45 | "create_username": '小丸子',
46 | "is_public": 2,
47 | "create_time": "2019-05-5"
48 | },
49 | {
50 | "id": 7,
51 | "title": "爱是淡淡的忧伤",
52 | "content": "回味初识的那一段深情爱恋,清晰的面容,熟悉的身影,悦耳的声音,在某个深夜恍然想起。那是一个深秋的夜晚,我们相拥而坐...",
53 | "see_count": 320,
54 | "like_count": 12,
55 | "share_count": 5,
56 | "create_username": '不值一提',
57 | "is_public": 1,
58 | "create_time": "2019-05-1"
59 | },
60 | {
61 | "id": 6,
62 | "title": "男人看了沉默,女人看了流泪",
63 | "content": "男人看了沉默,女人看了流泪男人看了沉默,女人看了流泪男人看了沉默,女人看了流泪男人看了沉默,女人看了流泪...",
64 | "see_count": 3220,
65 | "like_count": 11,
66 | "share_count": 1,
67 | "create_username": 'UC震惊部',
68 | "is_public": 1,
69 | "create_time": "2019-05-1"
70 | },
71 | {
72 | "id": 5,
73 | "title": "爱是淡淡的忧伤",
74 | "content": "回味初识的那一段深情爱恋,清晰的面容,熟悉的身影,悦耳的声音,在某个深夜恍然想起。那是一个深秋的夜晚,我们相拥而坐...",
75 | "see_count": 320,
76 | "like_count": 12,
77 | "share_count": 5,
78 | "create_username": '不值一提',
79 | "is_public": 1,
80 | "create_time": "2019-05-1"
81 | }
82 | ],
83 | dataCount: 6379
84 | }
85 |
--------------------------------------------------------------------------------
/src/sa-view/cfg/system-cfg.vue:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
服务器所有设置
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | 开启
27 | 关闭
28 |
29 |
30 | 保存修改
31 | 重置
32 |
33 |
34 |
35 |
36 |
37 |
38 |
78 |
--------------------------------------------------------------------------------
/src/sa-resources/com-view/sa-login.vue:
--------------------------------------------------------------------------------
1 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
SA-后台模板
33 |
34 |
35 |
账号登录
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | 登录
45 |
46 |
47 | 测试账号:sa/sa123456
48 | 暂不登录
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | Copyright ©2020 sa-admin模板 | xx省xxx网络科技有限公司 - 提供技术支持
57 |
58 |
59 |
60 |
61 |
91 |
92 |
--------------------------------------------------------------------------------
/src/sa-resources/sa-admin-init.js:
--------------------------------------------------------------------------------
1 | /*
2 | 在开发时,如无必要,请不要直接魔改模板的代码,以免在运行时出现意外bug
3 | 这是模板为你预留一个文件,用来对接你的业务逻辑
4 | */
5 |
6 | // import Vue from 'vue';
7 | export default function(sa_admin, sa) {
8 |
9 |
10 | // ================================= 示例:模板基础信息 =================================
11 | sa_admin.title = 'SA-后台模板';
12 | // sa_admin.logo_url = '图片地址'; // 设置logo图标地址 默认值空, 代表使用:./admin-logo.png
13 | // sa_admin.icon_url = '图片地址'; // 设置icon图标地址 默认值空, 代表使用:./favicon.ico
14 |
15 |
16 | // ================================= 示例:初始化菜单 =================================
17 | sa_admin.initMenu(); // 初始化菜单, 不传参代表默认显示所有菜单 菜单在 ./sa-menu-list.js 里,
18 | // sa_admin.initMenu(['1', '1-1', '1-2', '4']); // 传入一个id数组, 显示指定菜单
19 |
20 |
21 | // ================================= 示例:设置头像昵称 =================================
22 | //
23 | sa_admin.$nextTick(function() {
24 | sa_admin.user = {
25 | username: 'root', // 昵称
26 | avatar: document.querySelector('.admin-logo').src // 头像地址
27 | }
28 | })
29 |
30 |
31 | // ================================= 示例:js操作菜单 =================================
32 |
33 | // sa_admin.showHome(); // 显示主页选项卡
34 | // sa_admin.showTabById('home'); // 显示一个选项卡, 根据id
35 | // sa_admin.closeTabById('5-1'); // 关闭一个选项卡,根据 id ( 第二个参数可填关闭后的回调函数 )
36 | // sa_admin.showMenuById('5-2'); // 打开一个 菜单,根据 id
37 |
38 | // 跨窗口通信
39 | // sa_admin.getView('5-2').f5();// 获取指定视图的组件对象,并调用其f5()函数,一般用于跨窗口通信
40 |
41 | // 以下写法,调用tab打开新窗口
42 | // var tab = {id: '5-1', name: '用户添加', view: () => import('@/sa-view/user/user-add.vue'), params: {username: '王铁汉2'} };
43 | // sa_admin.showTab(tab);
44 |
45 |
46 | // ================================= 示例:设置登录后的头像处,下拉可以出现的选项 =================================
47 | sa_admin.dropList = [ // 头像点击处可操作的选项
48 | {
49 | name: '我的资料',
50 | click: function() {
51 | sa_admin.$message('点击了我的资料,你可以参照文档重写此函数');
52 | }
53 | },
54 | {
55 | name: '切换账号',
56 | click: function() {
57 | sa_admin.openLogin(); // 打开登陆视图
58 | }
59 | },
60 | {
61 | name: '退出登录',
62 | click: function() {
63 | // sa_admin.$message('点击了退出登录,你可以参照文档重写此函数');
64 | sa.confirm('退出登录?', function() {
65 | sa.ajax2('/acc/exit', function() {
66 | sa.alert('注销成功', function() {
67 | sa_admin.openLogin();
68 | })
69 | }, {msg: '正在注销'});
70 | });
71 | }
72 | }
73 | ]
74 |
75 |
76 | // 初始化模板, 必须调用
77 | sa_admin.init();
78 | // 或者这样:
79 | // sa_admin.init({
80 | // is_show_tabbar: false, // 关闭tabbar栏, 取而显示的是一个面包屑导航栏
81 | // is_reme_open: false // 是否记住上一次最后打开的窗口, 默认为true, 配置为false后, 每次刷新不再自动打开上一次最后打开的窗口(也不再有锚链接智能tab调准)
82 | // });
83 |
84 |
85 |
86 | // ================================= 关于鉴权 =================================
87 | // sa_admin内部封装了鉴权功能, 可以参考以下api
88 |
89 | // var arr = ['1', '2', '3', 'a', 'b', 'c']; // 一般由后端提供接口返回当前会话所具有的权限码集合
90 | // sa.setAuth(arr); // 设置当前账号具有的权限码集合
91 |
92 | // sa.checkAuth('a'); // 鉴权会通过
93 | // sa.checkAuth('y'); // 鉴权会失败, 弹窗提示无权限
94 |
95 | // sa.clearAuth(); // 在注销登录时, 可以清除当前会话所有权限码
96 |
97 | // // 具有指定权限才能显示某个按钮, 示例:
98 | // 删除
99 |
100 |
101 |
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # sa-admin (vue单页版)
3 |
4 | 一个多窗口后台模板,流畅、易上手、提高生产力,演示地址:[http://sa-vue-admin.dev33.cn](http://sa-vue-admin.dev33.cn)
5 |
6 | 如果你不太熟悉vue单页应用,[点我访问iframe版](https://github.com/click33/sa-admin)
7 |
8 | :kissing_closed_eyes: :kissing_closed_eyes: :kissing_closed_eyes: :kissing_closed_eyes: :kissing_closed_eyes: :kissing_closed_eyes: :kissing_closed_eyes: :kissing_closed_eyes: :kissing_closed_eyes: :kissing_closed_eyes: :kissing_closed_eyes: :kissing_closed_eyes: :blush: :blush: :blush: :heart: :heart: :heart:
9 |
10 | ## 优点
11 | - 上手简单:提供完整彻底的封装,不用修改一行源代码即可轻松集成
12 | - 示例全面:提供大量常见增删改查示例,提高你的生产力
13 |
14 | ## 需求提交
15 | - 我们深知一个优秀的项目需要海纳百川,[点我在线提交需求](http://sa-app.dev33.cn/wall.html?name=sa-admin)
16 |
17 |
18 | ## 框架选型
19 | - JS引擎:[Vue @2.6.11](https://cn.vuejs.org/)
20 | - 脚手架:[@vue/cli @4.0.5](https://cli.vuejs.org/zh/)
21 | - UI框架:[Element-UI @2.13.0](https://element.eleme.cn/#/zh-CN)
22 | - web弹层:[layer @3.1.1](http://layer.layui.com/)
23 | - 切页动画:[Swiper @4.5.0](https://www.swiper.com.cn/)
24 |
25 |
26 | ## 功能
27 | - 菜单:支持一、二、三级菜单,并开放一系列接口方便的使用js操作菜单
28 | - 主题:目前保留八种主题:蓝色、绿色、白色、灰色、灰色-展开、pro钛合金、沉淀式黑蓝、简约式灰蓝(切换主题时,可自动保存你的喜好,下次打开时仍然有效)
29 | - 折叠:折叠或收缩菜单,并且监听窗口大小变化,在拉伸窗口时自动折叠或收缩菜单,自动响应式
30 | - tabbar栏:
31 | - 卡片堆积:多卡片自动堆积,与菜单双向关联,切换tab卡时自动显示左侧菜单
32 | - 拖动手势:tab卡支持拖拽手势,上拖全屏打开、下拽悬浮打开、左拽快速关闭
33 | - 右键菜单:在tab上右击,可以:刷新、复制、关闭、关闭其它、关闭所有、悬浮打开、全屏打开、取消
34 | - 双击菜单:双击tabbar空白处,可以显示添加新tab窗口
35 | - 切换动画:集成swiper,滑动、淡入、方块、3D流、3D翻转,五种高大上切换动画,任你选择!
36 | - 开放接口:开放一系列api,助你方便的使用js操作tabbar栏,具体请查看集成文档
37 | - 锚链:tab切换自动更改hash锚链,同时监听锚链改变tab,可灵活的用鼠标前后键切换tab窗口 (如不需要此功能可在初始化时关闭)
38 | - 窗口:可在初始化时,设置是否显示tabbar栏,来控制它是多窗口还是单窗口,具体见使用文档
39 | - 更新:功能不断更新中... 你有好的想法也可以告诉我,加群一起交流吧
40 | - 文档:使用说明,见文档
41 |
42 |
43 | ## 开始使用
44 | #### 1、获取源码
45 | - 方式1:通过gitee或者github下载
46 | - 方式2:通过Git Bash:
47 | ```
48 | git clone https://github.com/click33/sa-vue-admin.git
49 | ```
50 |
51 | #### 2、运行
52 | - 获取源码后,在项目根目录执行cmd命令:
53 | ```
54 | 安装依赖:npm i
55 | 运行项目:npm run serve
56 | ```
57 | - 根据控制台输出的路径,访问浏览器,一般为:http://localhost:8080/
58 |
59 | #### 3、使用注意
60 | - 在开发时,如无必要,请不要直接魔改模板的代码,以免在运行时出现意外bug
61 | - 在 sa-resourecs 文件下,有个 sa-admin-init.js, 这是模板为你预留一个文件,用来对接你的业务逻辑
62 | - 在这个文件里,你可以:
63 | ```
64 | sa_admin.title = 'SA-后台模板'; // 设置模板标题
65 | sa_admin.logo_url = '图片地址'; // 设置logo图标地址 默认值空, 代表使用:./admin-logo.png
66 | sa_admin.icon_url = '图片地址'; // 设置icon图标地址 默认值空, 代表使用:./favicon.ico
67 | sa_admin.initMenu(); // 初始化菜单, 不传参代表默认显示所有菜单 菜单在 ./sa-menu-list.js 里定义,
68 | // sa_admin.initMenu(['1', '1-1', '1-2', '4']); // 传入一个id数组, 显示指定菜单
69 | // sa.checkAuth('a'); // 鉴权认证 (sa_admin内部封装了鉴权功能)
70 | sa_admin.init(); // 初始化模板, 必须调用
71 | ```
72 |
73 | - 以上示例在 sa-admin-init.js 文件里均有详细的注释说明,如果还要明白的地方,可以加入qq群询问
74 |
75 |
76 | ## 贡献代码
77 | 1. 在github上fork一份到自己的仓库
78 | 2. clone自己的仓库到本地电脑
79 | 3. 在本地电脑修改、commit、push
80 | 4. 提交pr(点击:New Pull Request)(提交pr前请保证自己fork的仓库是最新版本,如若不是先强制更新一下)
81 | 5. 等待合并
82 |
83 | ## 建议贡献的地方
84 | - 更多登录模板
85 | - 修复源码现有bug,或增加新的实用功能(比如:流畅的tab左右拖拽排序)
86 | - 更多demo示例:比如针对element-ui一些复杂组件的示例,或者其它一些常见js库的集成使用
87 | - 如果更新实用功能,可在文档友情链接处留下自己的推广链接
88 |
89 |
90 | ## QQ群
91 | QQ交流群:[782974737 点击加入](https://jq.qq.com/?_wv=1027&k=5DHN5Ib)
92 |
93 | ## 截图
94 |
95 | 
96 | 
97 | 
98 |
99 | 见演示说明地址
100 |
101 |
102 |
--------------------------------------------------------------------------------
/src/sa-resources/index/admin-util.js:
--------------------------------------------------------------------------------
1 | // ======================== 一些工具方法 ========================
2 |
3 | export default {
4 | // 删除数组某个元素
5 | arrayDelete: function(arr, item){
6 | var index = arr.indexOf(item);
7 | if (index > -1) {
8 | arr.splice(index, 1);
9 | }
10 | },
11 |
12 | //执行一个函数, 解决layer拉伸或者最大化的时候,iframe高度不能自适应的问题
13 | solveLayerBug: function(index) {
14 | var selected = '#layui-layer' + index;
15 | var height = $(selected).height();
16 | var title_height = $(selected).find('.layui-layer-title').height();
17 | $(selected).find('iframe').css('height', (height - title_height) + 'px');
18 | // var selected = '#layui-layer' + index;
19 | // var height = $(selected).height();
20 | // var title_height = $(selected).find('.layui-layer-title').height();
21 | // $(selected).find('iframe').css('height', (height - title_height) + 'px');
22 | },
23 |
24 | // 全屏
25 | fullScreen: function(){
26 | if(document.documentElement.RequestFullScreen){
27 | document.documentElement.RequestFullScreen();
28 | }
29 | //兼容火狐
30 | if(document.documentElement.mozRequestFullScreen){
31 | document.documentElement.mozRequestFullScreen();
32 | }
33 | //兼容谷歌等可以webkitRequestFullScreen也可以webkitRequestFullscreen
34 | if(document.documentElement.webkitRequestFullScreen){
35 | document.documentElement.webkitRequestFullScreen();
36 | }
37 | //兼容IE,只能写msRequestFullscreen
38 | if(document.documentElement.msRequestFullscreen){
39 | document.documentElement.msRequestFullscreen();
40 | }
41 | },
42 |
43 | // 退出全屏
44 | fullScreenNormal: function() {
45 | if(document.exitFullScreen){
46 | document.exitFullscreen()
47 | }
48 | // //兼容火狐
49 | // console.log(document.mozExitFullScreen)
50 | if(document.mozCancelFullScreen){
51 | document.mozCancelFullScreen()
52 | }
53 | // //兼容谷歌等
54 | if(document.webkitExitFullscreen){
55 | document.webkitExitFullscreen()
56 | }
57 | // //兼容IE
58 | if(document.msExitFullscreen){
59 | document.msExitFullscreen()
60 | }
61 | },
62 |
63 |
64 | // ======================== 菜单集合相关 ========================
65 |
66 | // 将一维平面数组转换为 Tree 菜单 (根据其指定的parent_id添加到其父菜单的childList)
67 | arrayToTree: function(menu_list) {
68 | for (var i = 0; i < menu_list.length; i++) {
69 | var menu = menu_list[i];
70 | // 添加到其指定的父菜单的childList
71 | if(menu.parent_id) {
72 | var parent_menu = this.getMenuById(menu_list, menu.parent_id);
73 | if(parent_menu) {
74 | parent_menu.childList = parent_menu.childList || [];
75 | parent_menu.childList.push(menu);
76 | menu_list.splice(i, 1); // 从一维中删除
77 | i--;
78 | }
79 | }
80 | }
81 | return menu_list;
82 | },
83 |
84 |
85 | // 将 menu_list 处理一下
86 | refMenuList: function(menu_list) {
87 | for (var i = 0; i < menu_list.length; i++) {
88 | var menu = menu_list[i];
89 | // 有子项的递归处理
90 | if(menu.childList){
91 | menu.children = menu.childList;
92 | this.refMenuList(menu.childList);
93 | }
94 | }
95 | return menu_list;
96 | },
97 |
98 |
99 |
100 | // 返回指定 index 的menu
101 | getMenuById: function(menuList, id) {
102 | for (var i = 0; i < menuList.length; i++) {
103 | var menu = menuList[i];
104 | if(menu.id + '' == id + '') {
105 | return menu;
106 | }
107 | // 如果是二级或多级
108 | if(menu.childList) {
109 | var menu2 = this.getMenuById(menu.childList, id);
110 | if(menu2 != null) {
111 | return menu2;
112 | }
113 | }
114 | }
115 | return null;
116 | }
117 |
118 |
119 |
120 |
121 | }
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/src/sa-view/role/menu-setup.vue:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
16 |
17 |
18 |
19 | 所有权限
20 |
21 |
34 |
35 | {{ s.data.name }}
36 | {{ s.data.name }} (隐藏)
37 | ———— {{s.data.info}}
38 |
39 |
40 |
41 |
42 |
43 |
47 |
48 |
49 |
50 |
115 |
--------------------------------------------------------------------------------
/src/sa-view/case/query-table-case-add.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | 正常
34 | 禁用
35 |
36 |
37 |
38 |
39 |
40 |
44 |
45 |
46 |
47 |
144 |
--------------------------------------------------------------------------------
/src/sa-view/article/art-add.vue:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
43 |
44 |
45 |
46 |
47 |
128 |
--------------------------------------------------------------------------------
/src/sa-view/case/submit-form.vue:
--------------------------------------------------------------------------------
1 |
4 |
5 |
6 |
7 |
8 |
9 |
表单提交
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | 参数1
41 | 参数2
42 | 参数3
43 |
44 |
45 |
46 | 苹果
47 | 鸭梨
48 | 香蕉
49 | 葡萄
50 |
51 |
52 |
53 | 正常
54 | 禁用
55 |
56 |
57 |
58 |
59 |
60 |
61 | 确定
62 |
63 |
64 |
65 |
66 |
67 |
68 |
128 |
--------------------------------------------------------------------------------
/src/sa-resources/sa-menu-list.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | // 一个菜单可以包括的所有属性
4 | // {
5 | // id: '12345', // 菜单id, 必须唯一
6 | // name: '用户中心', // 菜单名称, 同时也是tab选项卡上显示的名称
7 | // icon: 'el-icon-user', // 菜单图标, 参考地址: https://element.eleme.cn/#/zh-CN/component/icon
8 | // info: '管理所有用户', // 菜单介绍, 在菜单预览和分配权限时会有显示
9 | // view: () => import('@/sa-view/user/user-list.vue'), // 指向的视图
10 | // params: {}, // 视图参数
11 | // url: 'sa-html/user/user-list.html', // 菜单指向地址, 用iframe打开它 (配置后,view属性失效)
12 | // is_blank: false, // 如果指定了url, 此属性决定是否从新窗口打开
13 | // is_show: true, // 是否显示, 默认true
14 | // childList: [ // 指定这个菜单所有的子菜单, 子菜单可以继续指定子菜单, 至多支持三级菜单
15 | // // ....
16 | // ],
17 | // click: function(sa_admin, sa) { // 配置一个函数, 点击菜单时, 会执行这个函数
18 | // console.log(sa);
19 | // }
20 | // }
21 |
22 |
23 | /* 菜单集合 */
24 | export default [
25 | {
26 | id: '2',
27 | name: '各种示例',
28 | icon: 'el-icon-search',
29 | info: '增删改查各种常用组件示例',
30 | childList: [
31 | {id: '2-1', name: '查询参数示例', view: () => import('@/sa-view/case/query-p-case.vue')},
32 | {id: '2-2', name: '表格显示示例', view: () => import('@/sa-view/case/query-table-case.vue')},
33 | {id: '2-3', name: '表单提交示例', view: () => import('@/sa-view/case/submit-form.vue')}
34 | ]
35 | },
36 | {
37 | id: '3',
38 | name: '首页设置',
39 | icon: 'el-icon-table-lamp',
40 | info: '首页的一些设置',
41 | childList: [
42 | {id: '3-2', name: '轮播图设置', view: () => import('@/sa-view/home/swiper-list.vue')}
43 | ]
44 | },
45 | {
46 | id: '4',
47 | name: '权限控制',
48 | icon: 'el-icon-unlock',
49 | info: '对系统角色权限的分配等设计,敏感度较高,请谨慎授权',
50 | childList: [
51 | {id: '4-1', name: '角色列表', view: () => import('@/sa-view/role/role-list.vue') },
52 | {id: '4-2', name: '菜单预览', view: () => import('@/sa-view/role/menu-list.vue') }
53 | ]
54 | },
55 | {
56 | id: '5',
57 | name: '用户管理',
58 | icon: 'el-icon-user',
59 | info: '对用户列表、添加、统计等等...',
60 | childList: [
61 | {id: '5-2', name: '用户列表', view: () => import('@/sa-view/user/user-list.vue') },
62 | {id: '5-1', name: '用户添加', view: () => import('@/sa-view/user/user-add.vue'), params: {username: '王铁汉'} },
63 | ],
64 |
65 | // let template = '
';
66 | // menu.view = ()=> ({template: template});
67 |
68 | },
69 | {
70 | id: '6',
71 | name: '文章管理',
72 | icon: 'el-icon-document-copy',
73 | info: '对文章的增删改查、维护',
74 | childList: [
75 | {id: '6-1', name: '文章列表', view: () => import('@/sa-view/article/art-list.vue') },
76 | ]
77 | },
78 | // ========= 示例 指定一个函数, 点击菜单时执行这个函数 ================
79 | {
80 | id: '7',
81 | name: '系统设置',
82 | icon: 'el-icon-setting',
83 | childList: [
84 | {id: '7-1', name: '登录页', click: function(sa_admin, sa) { // 点击这个菜单时将执行这个函数
85 | console.log(sa_admin);
86 | console.log(sa);
87 | sa_admin.openLogin(); // 打开登录页面
88 | }},
89 | {id: '7-2', name: '403无权限', click: function(sa_admin) {
90 | sa_admin.open403(); // 打开403页面
91 | }},
92 | {id: '7-3', name: '404未找到', click: function(sa_admin) {
93 | sa_admin.open404(); // 打开404页面
94 | }},
95 | {id: '7-10', name: '500有错误', click: function(sa_admin) {
96 | sa_admin.open500(); // 打开500页面
97 | }},
98 | {id: '7-11', name: '服务器设置', view: () => import('@/sa-view/cfg/system-cfg.vue') },
99 | ]
100 | },
101 | // ========= 示例 外部链接 点击从新窗口打开 ================
102 | {
103 | id: '8',
104 | name: '外部链接',
105 | icon: 'el-icon-link',
106 | info: '示例:外部链接',
107 | childList: [
108 | {id: '8-1', name: '百度一下', url: 'https://www.baidu.com/', is_blank: true},
109 | {id: '8-6', name: '颜值排行榜', url: 'http://yanzhi21.com/', is_blank: true},
110 | {id: '8-7', name: 'jq22插件库', url: 'http://www.jq22.com/', is_blank: true},
111 | {id: '8-2', name: 'uni-app', url: 'https://uniapp.dcloud.io/', is_blank: true},
112 | {id: '8-11', name: 'sa-admin-iframe版', url: 'http://sa-admin.dev33.cn/', is_blank: true},
113 | {id: '8-3', name: 'sa-token', url: 'http://sa-token.dev33.cn/',}, // iframe打开
114 | {id: '8-4', name: 'SqlFly', url: 'https://sqlfly.dev33.cn/',}, // iframe打开
115 | ]
116 | },
117 | {
118 | id: '9',
119 | name: '一个隐藏菜单',
120 | view: () => import('@/sa-view/role/role-list.vue'),
121 | is_show: false// 隐藏
122 | },
123 | {id: '1-11', name: '在线论坛', url: 'http://applist.dev33.cn/applist-admin/html/ser-comment/w-list.html?sid=4nqjfqbyw6fh', is_show: false},
124 |
125 |
126 |
127 | ]
128 |
129 |
--------------------------------------------------------------------------------
/src/sa-view/article/art-list.vue:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
检索参数
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | 查询
18 | 增加
19 |
20 |
21 |
22 |
23 | 发表时间
24 | 喜欢数
25 | 点击数
26 | 分享数
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | 修改
44 | 删除
45 |
46 |
47 |
48 |
49 |
50 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 | wangEditor:
66 |
67 | 基于javascript和css开发的 Web富文本编辑器, 轻量、简洁、易用、开源免费
68 |
69 |
70 |
71 | 在vue中集成示例:
72 |
73 | https://www.kancloud.cn/wangfupeng/wangeditor3/335789
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
135 |
--------------------------------------------------------------------------------
/src/sa-view/role/role-list.vue:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
检索参数
10 |
11 |
12 |
13 |
14 |
15 | 查询
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | {{s.row.is_lock == 1 ? '是' : '否'}}
34 |
35 |
36 |
37 |
38 | {{sa.forDate(s.row.create_time)}}
39 |
40 |
41 |
42 |
43 |
44 | 修改
45 |
46 | 删除
47 | 分配权限
48 |
49 |
50 |
51 |
52 |
53 |
54 |
添加一个
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | {{m.is_lock == 1 ? '是' : '否'}}
74 |
75 |
76 |
77 |
78 | 添加
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
165 |
--------------------------------------------------------------------------------
/src/sa-view/user/user-list.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
用户列表
6 |
7 |
8 |
9 |
10 |
11 | -
12 |
13 |
14 |
15 | 查询
16 |
17 |
18 |
19 |
20 | 注册时间
21 | 最近登录
22 | 登陆次数
23 | 最近签到
24 | 签到次数
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
35 |
36 |
{{s.row.username}}
37 |
{{s.row.tell}}
38 |
39 |
40 |
41 |
42 |
43 |
44 | 共{{s.row.photo_list.length}}张, 点击预览
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | 正常
54 | 禁用
55 |
56 |
57 |
58 |
59 | 详情
60 | 删除
61 |
62 |
63 |
64 |
65 |
66 |
74 |
75 |
76 |
77 |
78 |
79 | layer:
80 | 一个可以让你想到即可做到的JavaScript弹窗(层)解决方案
81 |
82 |
83 |
84 |
85 |
86 |
139 |
140 |
142 |
--------------------------------------------------------------------------------
/src/sa-view/case/query-table-case.vue:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
检索参数
9 |
10 |
11 |
12 |
13 |
14 | 查询
15 | 添加
16 |
17 |
18 |
19 |
数据列表
20 |
21 |
22 |
23 |
24 |
25 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 | ¥{{s.row.money / 100}}
37 |
38 |
39 |
40 |
41 | 正常
42 | 禁用
43 |
44 |
45 |
51 |
52 |
53 |
54 | 正常
55 | 禁用
56 |
57 |
58 |
59 | {{sa.forDate(s.row.create_time, 2)}}
60 |
61 |
62 |
63 | 查看
64 | 修改
65 | 删除
66 |
67 |
68 |
69 |
70 | 查看
71 | 修改
72 | 删除
73 |
74 |
75 |
76 |
77 |
78 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
160 |
--------------------------------------------------------------------------------
/src/static/sa.css:
--------------------------------------------------------------------------------
1 | /** 公共css */
2 | *{margin: 0px;padding: 0px;}
3 | html{font-size: 10px; height: 100%;}
4 | body{font-size: 1.4rem; height: 100%; background-color: #eeeeee; color: #333;}
5 | body{font-family: "Helvetica Neue", Helvetica, "PingFang SC", Tahoma, Arial, sans-serif;}
6 | a{text-decoration: none;}
7 | a:hover{}
8 | /* h1,h2,h3,h4,h5,h6{font-weight: 400;} */
9 | hr{background-color : #ddd; height: 1px; border: none;}
10 | input,select{outline: 0;}
11 |
12 | /* input type=number时不显示按钮 */
13 | input::-webkit-outer-spin-button,
14 | input::-webkit-inner-spin-button {
15 | -webkit-appearance: none !important;
16 | margin: 0;
17 | }
18 |
19 | /* 居中形式的img */
20 | .cover-img{object-fit: cover; object-position: 50% 30%;}
21 |
22 | /* ajax2加载时的转圈圈样式 */
23 | .ajax-layer-load.layui-layer-dialog{min-width: 0px !important; background-color: rgba(0,0,0,0.85);}
24 | .ajax-layer-load.layui-layer-dialog .layui-layer-content{padding: 10px 20px 10px 40px; color: #FFF;}
25 | .ajax-layer-load.layui-layer-dialog .layui-layer-content .layui-layer-ico{width: 20px; height: 20px; background-size: 20px 20px; top: 12px; }
26 |
27 |
28 | /* layer图片预览时, 左右键永远显示 */
29 | .layui-layer-imgbar, .layui-layer-imguide{display: block !important;}
30 | .layui-layer-iconext.layui-layer-imgprev{position: fixed; left: 50;}
31 | .layui-layer-iconext.layui-layer-imgnext{position: fixed; right: 50;}
32 |
33 |
34 | /* ===================== 整体面板 ===================== */
35 | /* vue盒子 */
36 | .vue-box{/* padding-bottom: 20px; */font-size: 14px; width: 100%; height: 100%; overflow: auto; background-color: #EEE;}
37 |
38 | /* 内容-面板 */
39 | .c-panel{margin: 1em 1em; padding: 1em 1.5em; background-color: #fff; color: #333; /* box-shadow: 0 0 5px #eee; */}
40 | .c-title{font-size: 14px; font-weight: bold; line-height: 2em; margin-bottom: 3px;}
41 | .c-title span{font-weight: 400; font-size: 0.85em; padding-left: 1em; color: #888;}
42 |
43 |
44 | /* ===================== 表单相关 ===================== */
45 | .c-panel .el-form{padding-top: 10px; padding-bottom: 5px;}
46 | .c-panel .el-form-item{min-width: 278px;}
47 | .c-panel .el-form-item__label,.c-panel .c-label{width: 100px;}
48 | .c-panel .c-label{display: inline-block;}
49 | .c-panel .el-form .el-input{width: 178px;}
50 | .c-remark{color: #888; margin-left: 0.5em; font-size: 0.9em;}
51 |
52 | /* 标签 */
53 | .c-panel .c-tag{padding: 0px 15px; height: 22px; line-height: 22px; border-radius: 0px; border: 0px;}
54 | /* 复选框 */
55 | .c-panel .el-checkbox,.c-panel .el-radio{margin-right: 20px;}
56 | /* 禁用input的样式 */
57 | .c-panel .el-input.is-disabled .el-input__inner{color: #999;}
58 |
59 | /* 表格的表头颜色深一点 */
60 | .c-panel .el-table__header tr th{background-color: #F5F5F5;}
61 |
62 | /* 调整圆角大小: 输入框、文本域、按钮、 */
63 | .c-panel .el-input__inner,
64 | .c-panel .el-textarea__inner,
65 | .c-panel .el-button{border-radius: 2px !important;}
66 |
67 |
68 | /* 单选button,圆角限制2px */
69 | .el-radio-button:first-child .el-radio-button__inner{border-radius: 2px 0 0 2px !important;}
70 | .el-radio-button:last-child .el-radio-button__inner{border-radius: 0 2px 2px 0 !important;}
71 |
72 | /* 单选按钮, 文字版 */
73 | .s-radio-text{}
74 | .s-radio-text .el-radio__input{display: none;}
75 | .s-radio-text .el-radio__input.is-checked+.el-radio__label{font-weight: 700;}
76 | .s-radio-text .el-radio__label{padding-left: 0px; }
77 | .s-radio-text .el-radio__label:hover{text-decoration:underline;}
78 | .s-radio-text .hover-line:hover{text-decoration: underline; cursor: pointer;}
79 | .s-radio-text .el-form-item__content{position: relative; top: -2px;}
80 |
81 | /* 表格里操作按钮的样式调整 */
82 | .c-btn{padding: 4px 6px; font-size: 12px !important; border-radius: 1px;}
83 | .c-btn.el-button--primary{background-color: #3296FA;}
84 | .c-btn.el-button--primary:hover{background-color: #067CF3; border-color: #067CF3;}
85 | .c-btn.el-button--danger{background-color: #CA4242;}
86 | .c-btn.el-button--danger:hover{background-color: #A00C0C; border-color: #A00C0C;}
87 | .c-btn.el-button--success:hover{background-color: #2B9939; border-color: #2B9939;}
88 |
89 | /* 分页盒子调整一下间距 */
90 | .page-box{padding: 2em 0 1em 0; }
91 |
92 | /* ===================== 一些特殊元素 ===================== */
93 |
94 |
95 | /* 流体表单 */
96 | .cj-form.vue-box{padding-bottom: 0px; height: 100vh; background-color: #FFF;}
97 | .cj-form .c-panel{box-shadow: 0 0 0; margin-top: 0px; margin-bottom: 0px; padding-top: 2.5em; padding-bottom: 0px;}
98 | .cj-form .c-panel .el-form .el-input{width: 100%;}
99 |
100 | /* 没有内边距的dialog */
101 | .full-dialog .el-dialog__body{padding: 0px;}
102 | .full-h-dialog .el-dialog__header{padding: 0px;}
103 | /* .full-dialog .el-dialog__header{padding: 0px;} */
104 |
105 | .iframe-view-box{width: 100%; height: 100%; overflow: hidden;}
106 | .iframe-view{width: 100%; height: 100%; border: 0px; background-color: #EEE;}
107 |
108 |
109 | /* ===================== 表单相关 - 旧方案 ===================== */
110 |
111 | /* 内容-item */
112 | .c-item {min-width: 280px; min-height: 32px; line-height: 32px; padding-right: 20px; display: inline-block; margin: 0.5em 0;}
113 | .c-item.br{display: block;}
114 | /* label样式 */
115 | .c-item .c-label{width: 5em; color: #333; display: inline-block; text-align: right;}
116 | /* input宽度等样式调整 */
117 | .c-item .el-input{width: 200px;}
118 | /* 禁用input的样式 */
119 | .c-item .el-input.is-disabled .el-input__inner{color: #999;}
120 | /* 链接 行高设置 */
121 | .c-item .el-link{line-height: 1.6em;}
122 |
123 |
124 | /* ===================== 自定义一下滚动条 ===================== */
125 | /*滚动条的宽度*/
126 | .vue-box::-webkit-scrollbar {width:9px;height:9px;}
127 |
128 | /*外层轨道。可以用display:none让其不显示,也可以添加背景图片,颜色改变显示效果*/
129 | .vue-box::-webkit-scrollbar-track {
130 | width: 6px;
131 | background-color:#F1F1F1;
132 | -webkit-border-radius: 2em;
133 | -moz-border-radius: 2em;
134 | border-radius:2em;
135 | }
136 | /*滚动条的设置*/
137 | .vue-box::-webkit-scrollbar-thumb {
138 | background-color:#C1C1C1;
139 | background-clip:padding-box;
140 | min-height:28px;
141 | -webkit-border-radius: 2em;
142 | -moz-border-radius: 2em;
143 | border-radius:2em;
144 | }
145 | /*滚动条移上去的背景*/
146 | /* .vue-box::-webkit-scrollbar-thumb:hover {background-color:#fff;} */
--------------------------------------------------------------------------------
/src/sa-view/home/swiper-list.vue:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
检索参数
11 |
12 |
13 |
14 |
15 |
16 | 查询
17 |
18 |
19 |
20 |
21 | 排序值
22 | 创建时间
23 | 点击量
24 |
25 |
26 |
27 |
28 |
数据列表
29 |
30 |
31 |
32 |
33 |
34 | 点击预览
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | 显示
52 | 隐藏
53 |
54 |
55 |
56 | {{sa.forDate(s.row.create_time, 2)}}
57 |
58 |
59 |
60 |
61 | 修改
62 |
63 |
64 | 删除
65 |
66 |
67 |
68 |
69 |
70 |
71 |
79 |
80 |
81 |
82 |
83 |
84 |
添加一个
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
101 |
102 |
103 | 添加
104 |
105 |
106 |
107 |
108 |
109 |
110 |
177 |
178 |
--------------------------------------------------------------------------------
/src/sa-view/case/query-p-case.vue:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
检索参数
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | 查询
25 |
26 |
27 |
28 |
29 |
30 |
31 | -
32 |
33 |
34 |
35 |
36 |
37 | 参数1
38 | 参数2
39 |
40 |
41 |
42 |
43 | 参数1
44 | 参数2
45 | 参数3
46 | 参数4
47 |
48 |
49 |
50 |
51 |
52 | 全部
53 | 新下单
54 | 已支付
55 | 已发货
56 | 已收货
57 | 已评价
58 | 取消中
59 | 退款中
60 |
61 |
62 |
63 |
64 | 已上架
65 | 已推荐
66 | 热卖中
67 | 高点击
68 | 高转化
69 | 高复买
70 |
71 |
72 |
73 |
数据列表
74 |
75 |
76 |
77 |
78 |
79 |
80 | 查看
81 | 修改
82 | 删除
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
180 |
--------------------------------------------------------------------------------
/src/sa-resources/index/sa-index.css:
--------------------------------------------------------------------------------
1 | /* index样式(局部样式) */
2 | *{margin: 0; padding: 0; }
3 | html,body{height: 100%; background-color: #EEE;}
4 | .app{height: 100%; font-size: 16px; font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",Arial,sans-serif;}
5 | /* .app *{transition: all 0.2s !important; } */
6 |
7 |
8 | /* 左边 */
9 | .nav-left{
10 | width: 200px;
11 | height: 100%;
12 | position: fixed;
13 | left: 0px;
14 | z-index: 110;
15 | overflow: hidden;
16 | transition: all 0.2s;
17 | }
18 | .nav-left *{transition: all 0.2s !important; }
19 | /* 左上 logo部分 */
20 | .nav-left-top{width: 100%; height: 85px; overflow: hidden; line-height: 85px; cursor: pointer; transform: none;}
21 | .nav-left .admin-logo{width: 40px; height: 40px; border-radius: 50%; vertical-align: middle; margin: 0.5em; margin-left: 1em; margin-right: 0.7em;}
22 | /* ==== .nav-left-top:hover{color: #FFF;} */
23 |
24 | /* 左下 */
25 | .nav-left-bottom{
26 | width: 100%;
27 | height: calc(100% - 80px);
28 | overflow: hidden;
29 | }
30 | .nav-left-bottom i[class^=el-icon-]{font-size: 16px;}
31 |
32 | /* 1 2 配合,把滚动条隐藏 */
33 | .nav-left .menu-box-1{width: 220px; height: 100%; overflow-y: auto;}
34 | .nav-left .menu-box-2{width: 201px;}
35 |
36 | .nav-left .el-submenu__title .menu-name{margin-left: 4px;}
37 |
38 | /* 尺寸调整, 二级和三级的左内边距向右扩大 */
39 | .nav-left .el-submenu__title,.nav-left .el-menu-item{height: 45px !important; line-height: 45px !important;}
40 | .nav-left .el-submenu .el-menu-item,.nav-left .el-submenu .el-submenu .el-submenu__title{height: 40px !important; line-height: 40px !important; padding-left: 4em !important;}
41 |
42 | .nav-left .el-submenu .el-submenu .el-menu-item{padding-left: 5em !important;}
43 |
44 | /* 隐藏右边框 */
45 | .nav-left .el-menu{border: 0px;}
46 |
47 |
48 | /* -------- 右边 --------- */
49 | .nav-right{
50 | width: calc(100% - 200px);
51 | height: 100%;
52 | position: fixed;
53 | left: 200px;
54 | transition: all 0.2s;
55 | }
56 |
57 | /* 第一行建筑物 */
58 | .nav-right-1{position: relative; height: 49px; line-height: 49px; border-bottom: 1px #DDD solid; }
59 | .nav-right-1 *{transition: all 0.2s;}
60 |
61 | .nav-right-1 .tools-left{border: 0px #000 solid; float: left;}
62 | .nav-right-1 .tools-right{float: right;}
63 | .nav-right-1 .tool-fox{padding: 0 1em; margin-right: 4px; display: inline-block; cursor: pointer;}
64 | .nav-right-1 .tool-fox i{margin-right: 3px;}
65 |
66 | .nav-right-1 .user-info{position: relative; top: -2px;}
67 | .nav-right-1 .user-avatar{width: 30px; height: 30px; border-radius: 50%; vertical-align: middle;}
68 | .nav-right-1 .user-info .user-name{font-size: 0.9em;}
69 |
70 |
71 | /*800px之下*/
72 | @media(max-width: 800px) {
73 | .nav-right-1 .tools-right{display: none;}
74 | }
75 |
76 | /* 第二行建筑物 */
77 | .nav-right-2,.nav-right-bre{height: 35px; position: relative; z-index: 110; box-shadow: 0 2px 2px #CCC;}
78 | .nav-right-2>div{height: 100%; position: absolute;}
79 |
80 | .nav-right-bre{line-height: 35px; padding-left: 1em; background-color: #FFF; cursor: pointer; display: none;}
81 | .nav-right-bre .el-breadcrumb__item{line-height: 35px; font-size: 13px; }
82 | /* .nav-right-bre .el-breadcrumb__item:hover{cursor: pointer; text-decoration: underline;} */
83 |
84 | .nav-right-2 .towards-left,.nav-right-2 .towards-right{width: 24px; text-align: center; background-color: #FFF; cursor: pointer; line-height: 35px;}
85 | .nav-right-2 .towards-left{border-right: 1px #eee solid;}
86 | .nav-right-2 .towards-right{border-left: 1px #eee solid; right: 0px;}
87 | .nav-right-2 .towards-left:hover i,.nav-right-2 .towards-right:hover i{font-size: 1.1em;font-weight: bold;}
88 |
89 | .nav-right-2 .towards-middle{width: 10000px; overflow: auto;/* calc(100% - 50px) */ left: 25px;background-color: #EEE;}
90 | .nav-right-2 .tab-title-box{display: inline-block; position: absolute; left: 0px; transition: all 0.2s;}
91 | .nav-right-2 .tab-title{font-size: 13px; cursor: pointer; float: left; transition: all 0.15s;white-space: nowrap;overflow: hidden;text-decoration: none; color: #333;}
92 | .nav-right-2 .tab-title-2{padding: 0px 10px; height: 35px; margin-right: 1px; background-color: #FFF; line-height: 35px; }
93 | .nav-right-2 .tab-title-2{transition: padding 0.1s, margin 0.1s;}
94 | .nav-right-2 .tab-title-2 *{transition: all 0.0s;}
95 | /* .tab-title .el-icon-caret-right{color: #EEE; font-size: 1.7em; position: relative; top: 4px;} */
96 | .nav-right-2 .tab-title .el-icon-close{display: inline-block; border-radius: 50%; padding: 1px; color: #ccc; margin-left: -4px;}
97 | .nav-right-2 .tab-title .el-icon-close:hover{background-color: red; color: #FFF;}
98 | .nav-right-2 .tab-title span{display: inline-block; margin-left: 10px; margin-right: 10px;}
99 | .nav-right-2 .tab-title:hover span,.nav-right-2 .tab-native span{font-weight: bold;}
100 |
101 | /* 第三杠 */
102 | .nav-right-3{width: 100%; height: calc(100% - 85px); position: relative; overflow: hidden;}
103 | .sa-swiper{width: 100%; height: 100%;}
104 | .view-fox{width: 100%; height: 100%; overflow: auto; background-color: #EEE;}
105 | .view-fox>*{width: 100%; height: 100%; overflow: auto;}
106 |
107 | /* .fas{transition: all 0s;} */
108 | .at-form-fox,
109 | .at-form-fox *{transition: all 0s;}
110 |
111 | /* 右键菜单 样式 */
112 | .right-box {
113 | position: fixed;
114 | z-index: 2147483647;
115 | transition: max-height 0.2s;
116 | outline:none;
117 | max-height: 0px;
118 | overflow: hidden;
119 | box-shadow: 3px 3px 3px #666;
120 | }
121 | .right-box-2{font-size: 0.8em; padding: 0.5em 0; border: 1px #aaa solid; border-radius: 1px; background-color: #FFF;}
122 | .right-box-2>div {line-height: 2.2em; padding-left: 0.7em; padding-right: 1.8em; cursor: pointer; white-space: nowrap;}
123 | .right-box-2>div:hover {background-color: #ddd;color: #2D8CF0;}
124 | .right-box-2>div i{ margin-right: 8px;}
125 |
126 |
127 | /* 菜单折叠时候样式调整 */
128 | .fold .nav-left{width: 64px;}
129 | .fold .nav-left .admin-logo{width: 40px; height: 40px; margin-left: 0.8em;}
130 | .fold .nav-right{width: calc(100% - 64px); left: 64px; }
131 | /* .app .is_fold_right.nav-right{width: calc(100% - 64px); left: 64px; } */
132 |
133 | /* .nav-right-3 包裹了太多iframe,不能让它参与动画,因为实在太TM卡了 */
134 | .nav-right-3{ /* 修改为fixed布局 */ width: calc(100% - 200px); left: 200px; position: fixed;}
135 | .is_fold_right .nav-right-3{width: calc(100% - 64px); left: 64px;}
136 |
137 |
138 |
139 | /* 菜单折叠时 部分元素隐藏 */
140 | .fold .nav-left .nav-title,
141 | .fold .nav-left .menu-name,
142 | .fold .nav-left .el-submenu__icon-arrow
143 | {display: none;}
144 |
145 | /* 最高层级 */
146 | .z-index-max{z-index: 2147483647;}
147 |
148 |
149 | /* 遮罩样式 */
150 | .shade-fox{position: absolute; z-index: 1000000; width: 100%; height: 100%; background-color: rgba(0,0,0,0.5); color: #FFF; top: 0px;}
151 | .shade-fox{display: flex; justify-content: center; align-items: center}
152 |
153 |
154 | /* 如果是隐藏tabbar模式 */
155 | .hide-tabbar .nav-right-2{display: none;}
156 | .hide-tabbar .nav-right-bre{display: block;}
157 | .hide-tabbar .nav-right-1{border-bottom: 1px #eeeeee solid;}
158 |
159 |
160 | /* 去除掉便签的大边框 */
161 | .layui-layer-input{outline: 0; box-shadow: none !important; padding: 0.5em !important; font-family: 'Times New Roman', Times, serif;}
162 |
163 | /*
164 | 所有污染样式:
165 | .nav-* .at-form-fox .shade-fox
166 | */
--------------------------------------------------------------------------------
/src/sa-resources/index/sa-theme.css:
--------------------------------------------------------------------------------
1 | /* index样式(主题样式) */
2 |
3 | /* 样式调整为继承父级 */
4 | .app .nav-left .el-submenu__title i,
5 | .app .nav-left .el-menu-item i,
6 | .app .nav-right-1 .el-dropdown,
7 | .app .nav-right-2 .tab-title:hover .el-icon-caret-right,
8 | .app .nav-right-2 .tab-title.tab-native .el-icon-caret-right {
9 | color: inherit;
10 | }
11 |
12 | .app .nav-left .el-menu,
13 | .app .nav-left .el-submenu,
14 | .app .nav-left .el-submenu__title,
15 | .app .nav-left .el-submenu .el-submenu .el-submenu__title,
16 | .app .nav-left .el-menu-item {
17 | color: inherit;
18 | background-color: inherit;
19 | }
20 |
21 | /* 切换主题时,停止动画 */
22 | .app .themeToggling .nav-left,.themeToggling .nav-left *{transition: none !important;}
23 | .app .themeToggling .nav-left-top,.themeToggling .nav-left-top *{transition: all 0.2s !important;}
24 |
25 |
26 | /* ========================== 主题 - 0 默认样式 蓝色 ========================== */
27 | .theme-0 {}
28 |
29 | /* 左边栏背景色,前景色 */
30 | .theme-0 .nav-left {
31 | background-color: #222;
32 | color: #FFF;
33 | }
34 |
35 | /* 二级菜单背景色 */
36 | .theme-0 .nav-left .el-submenu .el-menu-item,
37 | .theme-0 .nav-left .el-submenu .el-submenu .el-submenu__title{
38 | background-color: #000;
39 | }
40 |
41 | /* 所有菜单悬浮样式*/
42 | .theme-0 .nav-left .el-submenu__title:hover,
43 | .theme-0 .nav-left .el-submenu .el-submenu .el-submenu__title:hover,
44 | .theme-0 .nav-left .el-menu-item:hover{
45 | background-color: #4E5465;
46 | }
47 | /* 所有菜单选中时 */
48 | .theme-0 .nav-left .el-menu-item.is-active {
49 | background-color: #2D8CF0;
50 | color: #FFF;
51 | }
52 |
53 | /* 工具栏背景色颜色, 前景色 */
54 | .theme-0 .nav-right-1 {
55 | color: #333;
56 | background-color: #FFF;
57 | }
58 |
59 | /* 工具栏悬浮颜色 */
60 | .theme-0 .nav-right-1 .tool-fox:hover {
61 | background-color: #EEE;
62 | }
63 |
64 | /* 卡片栏悬浮颜色和选中颜色 */
65 | .theme-0 .nav-right-2 .tab-title:hover,
66 | .theme-0 .nav-right-2 .tab-native.tab-title {
67 | color: #2D8CF0;
68 | }
69 |
70 |
71 | /* ========================== 主题-1 什么也不覆盖 即:全部取默认样式 ========================== */
72 | .theme-1 {}
73 |
74 | /* ========================== 主题-2 绿色 ========================== */
75 | .theme-2 {}
76 |
77 | /* 所有菜单选中时 */
78 | .theme-2 .nav-left .el-menu-item.is-active {
79 | background-color: #009688;
80 | }
81 |
82 | /* 卡片栏悬浮颜色和选中颜色 */
83 | .theme-2 .nav-right-2 .tab-title:hover,
84 | .theme-2 .nav-right-2 .tab-native.tab-title {
85 | color: #009688;
86 | }
87 |
88 | /* ========================== 主题-3 白色 清爽 ========================== */
89 | .theme-3 {}
90 |
91 | /* 非标准附加样式 */
92 | .theme-3 .nav-left-top{box-shadow: 0 2px 2px #CCC; width: 199px; border-right: 1px #DDD solid;}
93 | .theme-3 .nav-left-bottom{width: 199px; border-right: 1px #DDD solid;}
94 | .theme-3.fold .nav-left-bottom{width: 63px;}
95 | /* .theme-3 .nav-right-1,.theme-3 .nav-right-2{border-left: 1px #eee solid;} */
96 |
97 | /* 左边栏背景色,前景色 */
98 | .theme-3 .nav-left {
99 | background-color: #FFF;
100 | color: #333;
101 | }
102 |
103 | /* 二级菜单背景色 */
104 | .theme-3 .nav-left .el-submenu .el-menu-item,
105 | .theme-3 .nav-left .el-submenu .el-submenu .el-submenu__title{
106 | background-color: #fafafa;
107 | }
108 |
109 | /* 所有菜单悬浮样式时, 以及选中时 */
110 | .theme-3 .nav-left .el-submenu__title:hover,
111 | .theme-3 .nav-left .el-submenu .el-submenu .el-submenu__title:hover,
112 | .theme-3 .nav-left .el-menu-item:hover,
113 | .theme-3 .nav-left .el-menu-item.is-active {
114 | background-color: #ECF5FF;
115 | color: #409EFF;
116 | }
117 |
118 |
119 | /* ========================== 主题-4 上黑 下白 ========================== */
120 | .theme-4 {}
121 |
122 | /* 非标准附加样式 */
123 | .theme-4 .nav-left-top{height: 49px; line-height: 49px; text-indent: 2em; background-color: #222; color: #EEE;}
124 | .theme-4 .nav-left-top .admin-logo{display: none;}
125 |
126 | .theme-4 .nav-left-bottom{width: 199px; border-right: 1px #DDD solid;}
127 | .theme-4.fold .nav-left-bottom{width: 63px;}
128 | .theme-4 .nav-left .el-submenu__title,
129 | .theme-4 .nav-left .el-menu-item{transition: background-color 0.1s;}
130 |
131 | /* 左边栏背景色,前景色 */
132 | .theme-4 .nav-left {
133 | background-color: #EEE;
134 | color: #333;
135 | }
136 |
137 | /* 二级菜单背景色 */
138 | .theme-4 .nav-left .el-submenu .el-menu-item,
139 | .theme-4 .nav-left .el-submenu .el-submenu .el-submenu__title{
140 | background-color: #DDD;
141 | }
142 |
143 | /* 所有菜单悬浮样式时 */
144 | .theme-4 .nav-left .el-submenu__title:hover,
145 | .theme-4 .nav-left .el-submenu .el-submenu .el-submenu__title:hover,
146 | .theme-4 .nav-left .el-menu-item:hover{
147 | background-color: #ECF5FF;
148 | }
149 | /* 所有菜单选中时 */
150 | .theme-4 .nav-left .el-menu-item.is-active {
151 | background-color: #009688;
152 | color: #FFF;
153 | }
154 |
155 | /* 卡片栏悬浮颜色和选中颜色 */
156 | .theme-4 .nav-right-2 .tab-title:hover,
157 | .theme-4 .nav-right-2 .tab-native.tab-title {
158 | color: #009688;
159 | }
160 |
161 | /* 工具栏背景色颜色, 前景色 */
162 | .theme-4 .nav-right-1 {
163 | color: #EEE;
164 | background-color: #222;
165 | }
166 |
167 | /* 工具栏悬浮颜色 */
168 | .theme-4 .nav-right-1 .tool-fox:hover {
169 | background-color: #444;
170 | }
171 |
172 |
173 |
174 | /* ========================== 主题-5 灰色站看 (仿微信公众平台)0分 ========================== */
175 |
176 | .theme-5 {}
177 |
178 | .theme-5 .nav-left-top{box-shadow: 0 2px 2px #CCC;}
179 | .theme-5 .nav-left-top,
180 | .theme-5 .nav-left-bottom{width: 199px; border-right: 1px #DDD solid;}
181 | .theme-5.fold .nav-left-bottom{width: 63px;}
182 | .theme-5 .nav-left .el-submenu__icon-arrow.el-icon-arrow-down{display: none;}
183 | .theme-5 .nav-left-bottom .menu-box-2{padding-bottom: 200px;}
184 |
185 | /* 左边栏背景色,前景色 */
186 | .theme-5 .nav-left {
187 | background-color: #EEE;
188 | color: #000;
189 | }
190 |
191 | /* 二级菜单背景色 */
192 | .theme-5 .nav-left .el-submenu .el-menu-item,
193 | .theme-5 .nav-left .el-submenu .el-submenu .el-submenu__title{
194 | background-color: #EEE;
195 | }
196 |
197 | /* 所有菜单悬浮样式时, 以及选中时 */
198 | .theme-5 .nav-left .el-submenu__title:hover,
199 | .theme-5 .nav-left .el-submenu .el-submenu .el-submenu__title:hover,
200 | .theme-5 .nav-left .el-menu-item:hover,
201 | .theme-5 .nav-left .el-menu-item.is-active:hover {
202 | background-color: #ddd;
203 | color: #1AAD5E;
204 | }
205 | .theme-5 .nav-left .el-menu-item.is-active {background-color: #eee; color: #1AAD5E;}
206 |
207 | /* 卡片栏悬浮颜色和选中颜色 */
208 | .theme-5 .nav-right-2 .tab-title:hover,
209 | .theme-5 .nav-right-2 .tab-native.tab-title {
210 | color: #1AAD5E;
211 | }
212 |
213 |
214 | /* ========================== 主题-6 钛合金 (仿 iview admin pro) ========================== */
215 | .theme-6 {}
216 |
217 | /* 所有菜单选中时 */
218 | .theme-6 .nav-left .el-menu-item.is-active {
219 | background-color: #805322;
220 | color: #FFF;
221 | }
222 |
223 | /* 卡片栏悬浮颜色和选中颜色 */
224 | .theme-6 .nav-right-2 .tab-title:hover,
225 | .theme-6 .nav-right-2 .tab-native.tab-title {color: #805322;}
226 |
227 | /* 工具栏背景色颜色, 前景色 */
228 | .theme-6 .nav-right-1 {color: #EEE;background-color: #222;}
229 |
230 | /* 工具栏悬浮颜色 */
231 | .theme-6 .nav-right-1 .tool-fox:hover {background-color: #444;}
232 |
233 |
234 | /* ========================== 主题-7 沉淀式黑蓝 ========================== */
235 | .theme-7 {}
236 | /* 工具栏背景色颜色, 前景色 */
237 | .theme-7 .nav-right-1 {color: #EEE;background-color: #222;}
238 | /* 工具栏悬浮颜色 */
239 | .theme-7 .nav-right-1 .tool-fox:hover {background-color: #444;}
240 |
241 | /* ========================== 主题-8 简约式灰蓝 ========================== */
242 | .theme-8 {}
243 |
244 | /* 菜单悬浮着色 */
245 | .theme-8 .nav-left .el-menu-item.is-active {
246 | background-color: #4E5465;
247 | }
--------------------------------------------------------------------------------
/src/sa-resources/com-view/sa-home.vue:
--------------------------------------------------------------------------------
1 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 | Welcome to sa-admin (vue单页版)
34 | —— 一个多窗口后台模板,流畅、易上手、提高生产力
35 | 点我访问iframe版
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | 扫码加入QQ群交流
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | sa-admin (vue单页版)
52 |
53 |
54 |
55 | 本模板为 sa-admin (iframe版)
56 | 的升级版,与iframe版相比,单页版主要有以下两个优点:.vue模块化、es6新语法,技术选型也更加贴近主流,
57 | 如果你在使用时有任何问题,可以进行
58 | 意见提交
59 | 或点击下方的链接加入qq群(群里都是IT精英哦)
60 |
61 |
62 |
63 |
64 | QQ群:
65 | 782974737 点击加入
66 |
67 |
68 | 码云地址:
69 | https://gitee.com/click33/sa-vue-admin
70 |
71 |
72 | GitHub地址:
73 | https://github.com/click33/sa-vue-admin
74 |
75 |
79 |
80 | 新增需求墙:
81 | 点击打开,在线快速提交需求(新)
82 |
83 |
84 | 开源不易,求鼓励,给个star吧
85 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 | 技术选型
96 |
97 |
98 | JS引擎:Vue @2.6.11
99 | 脚手架:@vue/cli:@4.0.5
100 | UI框架:Element-UI @2.13.0
101 | web弹层:layer @3.1.1
102 | 切页动画:Swiper @4.5.0
103 | 富文本编辑器:wangEditor @3.1.1
104 | 没了:占空
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 | 功能介绍
115 |
116 |
117 |
118 | 窗口模式测试:
119 | 多窗口模式
120 | 单窗口模式
121 |
122 |
123 |
124 |
125 | 使用步骤
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 | 更新日志
137 |
138 |
139 |
140 |
141 |
142 |
143 | 版本 v1.0.3
144 | 2020-03-05
145 |
146 | 去除:去除tab双击刷新功能
147 |
148 |
149 |
150 |
151 | 版本 v1.0.2
152 | 2020-03-02
153 |
154 | 新增:新增tab双击刷新功能
155 |
156 |
157 |
158 |
159 | 版本 v1.0.1
160 | 2020-2-29
161 |
162 | 去除vue-router
163 | 增加sa_admin.getView函数,用于跨窗口通信
164 |
165 |
166 |
167 |
168 | 版本 v1.0.0
169 | 2020-2-29
170 |
171 | 第一个版本出炉
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
268 |
269 |
--------------------------------------------------------------------------------
/src/sa-view/user/data-list.js:
--------------------------------------------------------------------------------
1 | // 模拟数据
2 | module.exports = {
3 | code: 200,
4 | msg: 'ok',
5 | data: [{
6 | "id": 12001,
7 | "username": "省长",
8 | "avatar": "https://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/default_head/2.png?x-oss-process=style/yasuo",
9 | "tell": '这人懒,啥也没有留下',
10 | "sex": "男",
11 | "photo_list": [
12 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/02/02/1549112799839261454077.jpeg?x-oss-process=style/yasuo",
13 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/02/02/15491128027001242326540.jpeg?x-oss-process=style/yasuo",
14 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/02/02/1549112804446367923451.jpeg?x-oss-process=style/yasuo",
15 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/02/02/1549112806223866151639.jpeg?x-oss-process=style/yasuo",
16 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/02/02/15491128087691462190017.jpeg?x-oss-process=style/yasuo"
17 | ],
18 | "create_type": "账号注册",
19 | "create_time": "2019-02-09 20:22:00",
20 | "status": 1
21 |
22 | },
23 | {
24 | "id": 12002,
25 | "username": "小言",
26 | "avatar": "https://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/default_head/3.png?x-oss-process=style/yasuo",
27 | "tell": '人懒,啥也没留',
28 | "sex": "女",
29 | "photo_list": [
30 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/15486414241411760471758.jpg?x-oss-process=style/yasuo",
31 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548641424112923395306.jpg?x-oss-process=style/yasuo",
32 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548641424124307645243.jpg?x-oss-process=style/yasuo",
33 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/15486414241301079583057.jpg?x-oss-process=style/yasuo",
34 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/15486414241351214293219.jpg?x-oss-process=style/yasuo",
35 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548641424156586322884.jpg?x-oss-process=style/yasuo"
36 | ],
37 | "create_type": "账号注册",
38 | "create_time": "2019-02-11 13:22:41",
39 | "status": 1
40 |
41 | },
42 | {
43 | "id": 12003,
44 | "username": "旧城人凉",
45 | "avatar": "https://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/default_head/4.png?x-oss-process=style/yasuo",
46 | "tell": '人懒,啥也没留',
47 | "sex": "女",
48 | "photo_list": [
49 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/29/15487010332581464190738.jpg?x-oss-process=style/yasuo",
50 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/29/15487010332521119691172.jpg?x-oss-process=style/yasuo",
51 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/29/15487010332621622298950.jpg?x-oss-process=style/yasuo",
52 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/29/15487010332711954721691.jpg?x-oss-process=style/yasuo",
53 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/29/1548701033275197287565.jpg?x-oss-process=style/yasuo",
54 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/29/1548701033277157114772.jpg?x-oss-process=style/yasuo",
55 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/29/15487010332801673263633.jpg?x-oss-process=style/yasuo"
56 | ],
57 | "create_type": "账号注册",
58 | "create_time": "2019-02-11 8:22:56",
59 | "status": 1
60 |
61 | },
62 | {
63 | "id": 12004,
64 | "username": "苦巷深桥",
65 | "avatar": "https://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/default_head/5.png?x-oss-process=style/yasuo",
66 | "tell": '人懒,啥也没留',
67 | "sex": "女",
68 | "photo_list": [
69 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548641148401699190597.jpg?x-oss-process=style/yasuo",
70 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548641148403368860642.jpg?x-oss-process=style/yasuo",
71 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548641148447490522299.jpg?x-oss-process=style/yasuo",
72 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/15486411484491404458881.jpg?x-oss-process=style/yasuo",
73 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/15486411484521613746711.jpg?x-oss-process=style/yasuo",
74 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548641148452436812749.jpg?x-oss-process=style/yasuo"
75 | ],
76 | "create_type": "账号注册",
77 | "create_time": "2019-02-13 12:22:12",
78 | "status": 1
79 |
80 | },
81 | {
82 | "id": 12005,
83 | "username": "三重门",
84 | "avatar": "https://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/default_head/6.png?x-oss-process=style/yasuo",
85 | "tell": '人懒,啥也没留',
86 | "sex": "女",
87 | "photo_list": [
88 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548639217745410394722.jpg?x-oss-process=style/yasuo",
89 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/15486392177481726898108.jpg?x-oss-process=style/yasuo",
90 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/15486392177473938812.jpg?x-oss-process=style/yasuo",
91 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/15486392177582114379277.jpg?x-oss-process=style/yasuo",
92 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/15486392177631301168776.jpg?x-oss-process=style/yasuo"
93 | ],
94 | "create_type": "邮箱注册",
95 | "create_time": "2019-02-13 9:52:00",
96 | "status": 1
97 |
98 | },
99 | {
100 | "id": 12006,
101 | "username": "红尘几度欢颜笑",
102 | "avatar": "https://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/default_head/7.png?x-oss-process=style/yasuo",
103 | "tell": '人懒,啥也没留',
104 | "sex": "女",
105 | "photo_list": [
106 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/15486396582311677880214.jpg?x-oss-process=style/yasuo",
107 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/15486396582112088482959.jpg?x-oss-process=style/yasuo",
108 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/15486396582201751882045.jpg?x-oss-process=style/yasuo",
109 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548639658226225134395.jpg?x-oss-process=style/yasuo",
110 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/15486396582351948796029.jpg?x-oss-process=style/yasuo",
111 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548639658257423792653.jpg?x-oss-process=style/yasuo",
112 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548639658260413362409.jpg?x-oss-process=style/yasuo",
113 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/15486396582701933849474.jpg?x-oss-process=style/yasuo"
114 | ],
115 | "create_type": "邮箱注册",
116 | "create_time": "2019-03-13 20:12:54",
117 | "status": 1
118 | },
119 | {
120 | "id": 12007,
121 | "username": "许你春秋",
122 | "avatar": "https://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/default_head/8.png?x-oss-process=style/yasuo",
123 | "tell": '人懒,啥也没留',
124 | "sex": "女",
125 | "photo_list": [
126 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548638841214290095149.jpg?x-oss-process=style/yasuo",
127 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548638841227809145772.jpg?x-oss-process=style/yasuo",
128 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548638841240270928767.jpg?x-oss-process=style/yasuo",
129 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548638841244906005971.jpg?x-oss-process=style/yasuo",
130 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/154863884124713283459.jpg?x-oss-process=style/yasuo"
131 | ],
132 | "create_type": "邮箱注册",
133 | "create_time": "2019-03-16 20:22:00",
134 | "status": 1
135 | },
136 | {
137 | "id": 12008,
138 | "username": "李灵涵",
139 | "avatar": "https://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/default_head/9.png?x-oss-process=style/yasuo",
140 | "tell": '人懒,啥也没留',
141 | "sex": "女",
142 | "photo_list": [
143 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/15486374854182024752471.jpg?x-oss-process=style/yasuo",
144 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548637485458718538949.jpg?x-oss-process=style/yasuo",
145 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548637485455211731533.jpg?x-oss-process=style/yasuo",
146 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548637485460724239093.jpg?x-oss-process=style/yasuo",
147 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/15486374854672002390350.jpg?x-oss-process=style/yasuo",
148 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548637485473210846647.jpg?x-oss-process=style/yasuo",
149 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548637485471190844084.jpg?x-oss-process=style/yasuo"
150 | ],
151 | "create_type": "邮箱注册",
152 | "create_time": "2019-03-18 20:22:00",
153 | "status": 1
154 | },
155 | {
156 | "id": 12009,
157 | "username": "樱桃",
158 | "avatar": "https://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/default_head/10.png?x-oss-process=style/yasuo",
159 | "tell": '人懒,啥也没留',
160 | "sex": "女",
161 | "photo_list": [
162 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548637231837487154029.jpg?x-oss-process=style/yasuo",
163 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/15486372318271509628451.jpg?x-oss-process=style/yasuo",
164 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548637231848392706841.jpg?x-oss-process=style/yasuo",
165 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548637231857929283080.jpg?x-oss-process=style/yasuo",
166 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548637231873648635582.jpg?x-oss-process=style/yasuo"
167 | ],
168 | "create_type": "邮箱注册",
169 | "create_time": "2019-03-22 20:22:00",
170 | "status": 2
171 | },
172 | {
173 | "id": 12010,
174 | "username": "碘盐",
175 | "avatar": "https://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/default_head/1.png?x-oss-process=style/yasuo",
176 | "tell": '人懒,啥也没留',
177 | "sex": "女",
178 | "photo_list": [
179 | "http://color-test.oss-cn-qingdao.aliyuncs.com/dyc/img/2019/01/28/1548635034223276859883.jpg?x-oss-process=style/yasuo"
180 | ],
181 | "create_type": "手机号呢注册",
182 | "create_time": "2019-03-22 20:33:00",
183 | "status": 2
184 | },
185 | ],
186 | dataCount: 3306
187 | }
--------------------------------------------------------------------------------
/src/sa-resources/index/sa-index.vue:
--------------------------------------------------------------------------------
1 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
{{title}}
17 |
18 |
19 |
20 |
60 |
61 |
62 |
63 | 关闭
64 |
65 |
66 |
67 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | {{now_time}}
100 |
101 |
102 |
155 |
156 |
157 | 全屏打开
158 |
159 |
160 | 新窗口打开
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
176 |
177 |
178 | {{tab.name}}
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
191 |
192 |
193 |
194 |
195 |
196 | {{menu.name}}
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 | 拖拽至此:悬浮打开
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
刷新
222 |
复制
223 |
关闭
224 |
关闭其它
225 |
关闭所有
226 |
悬浮打开
227 |
全屏打开
228 |
新窗口打开
229 |
取消
230 |
231 |
232 |
233 |
234 |
235 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 |
254 |
255 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
265 |
266 |
267 |
268 |
269 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 |
294 | Copyright (C)
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | , 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------
/src/static/sa.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | import Vue from 'vue';
4 |
5 | // =========================== sa对象封装一系列工具方法 ===========================
6 | var sa = {
7 | version: '2.1',
8 | update_time: '2020-2-13',
9 | info: '改了loading框的样式'
10 | };
11 |
12 | // =========================== 当前环境配置 =======================================
13 | (function(){
14 | // 公司开发环境
15 | var cfg_dev = {
16 | api_url: 'http://localhost:8000', // 所有ajax请求接口父地址
17 | web_url: 'http://www.baidu.com' // 此项目前台地址 (此配置项非必须)
18 | }
19 | // 服务器测试环境
20 | var cfg_test = {
21 | api_url: 'http://www.baidu.com',
22 | web_url: 'http://www.baidu.com'
23 | }
24 | // 服务器测试环境
25 | var cfg_prod = {
26 | api_url: 'http://www.baidu.com',
27 | web_url: 'http://www.baidu.com'
28 | }
29 | sa.cfg = cfg_dev; // 最终环境 , 上线前请选择正确的环境
30 | })();
31 |
32 |
33 | // =========================== ajax的封装 =======================================
34 | (function(){
35 |
36 | /**
37 | 对jquery的ajax再封装, 包括: 全局的baseURL, 跨域配置, 自动loading图标, 自动的异常函数处理等等...
38 | 如果你觉得此函数难以理解, 也可以不用, 可以用你比较熟悉的原生写法
39 | 如果你对axios更熟悉, 也可以引入axios, 步骤为:
40 | 先在cmd中安装:
41 | npm install axios -S
42 | 然后在main.js里引入
43 | import axios from 'axios'
44 | Vue.prototype.$axios = axios;
45 | axios文档:
46 | https://www.kancloud.cn/yunye/axios/234845
47 | 在此暂不赘述
48 | 这个ajax假设你的接口会返回以下格式的内容
49 | {
50 | "code": 200,
51 | "msg": "ok",
52 | "data": []
53 | }
54 | 如果返回的不是这个格式, 你可能需要改动一下源码, 要么改动服务端适应此ajax, 要么改动这个ajax适应你的服务端
55 | * @param {Object} url 请求地址
56 | * @param {Object} data 请求参数
57 | * @param {Object} success200 当返回的code码==200时的回调函数
58 | * @param {Object} 其它配置,可配置项有:
59 | {
60 | msg: '', // 默认的提示文字 填null为不提示
61 | type: 'get', // 设定请求类型 默认post
62 | baseUrl: '', // ajax请求拼接的父路径 默认取 sa.cfg.apu_url
63 | sleep: 0, // ajax模拟的延时毫秒数, 默认0
64 | success500: fn, // code码等于500时的回调函数 (一般代表服务器错误)
65 | success403: fn, // code码等于403时的回调函数 (一般代表无权限)
66 | success401: fn, // code码等于401时的回调函数 (一般代表未登录)
67 | errorfn: fn, // ajax发生错误时的回调函数 (一般是ajax请求本身发生了错误)
68 | complete: fn, // ajax无论成功还是失败都会执行的回调函数
69 | }
70 | */
71 | sa.ajax = function(url, data, success200, cfg){
72 |
73 | // 如果是简写模式(省略了data参数)
74 | if(typeof data === 'function'){
75 | cfg = success200;
76 | success200 = data;
77 | data = {};
78 | }
79 |
80 | // 默认配置
81 | var defaultCfg = {
82 | msg: '努力加载中...', // 提示语
83 | baseUrl: (url.indexOf('http') === 0 ? '' : sa.cfg.api_url),// 父url,拼接在url前面
84 | sleep: 0, // 休眠n毫秒处理回调函数
85 | type: 'post', // 默认请求类型
86 | success200: success200, // code=200, 代表成功
87 | success500: function(res){ // code=500, 代表失败
88 | return layer.alert('失败:' + res.msg);
89 | },
90 | success403: function(res){ // code=403, 代表权限不足
91 | return layer.alert("权限不足," + res.msg, {icon: 5});
92 | },
93 | success401: function(res){ // code=401, 代表未登录
94 | return layer.confirm("您当前暂未登录,是否立即登录?", {}, function(){
95 | layer.closeAll();
96 | return Vue.prototype.sa_admin.openLogin();
97 | });
98 | },
99 | errorfn: function(error){ // ajax发生异常时的默认处理函数
100 | return layer.alert("异常:" + error.message);
101 | },
102 | complete: function(xhr, ts) { // 成功失败都会执行
103 |
104 | }
105 | }
106 |
107 | // 将调用者的配置和默认配置合并
108 | cfg = sa.extendJson(cfg, defaultCfg);
109 |
110 | // 打印请求地址和参数, 以便调试
111 | console.log("请求地址:" + cfg.baseUrl + url);
112 | console.log("请求参数:" + JSON.stringify(data));
113 |
114 | // 开始显示loading图标
115 | if(cfg.msg != null){
116 | sa.loading(cfg.msg);
117 | }
118 |
119 | // 开始请求ajax
120 | return $.ajax({
121 | url: cfg.baseUrl + url,
122 | type: cfg.type,
123 | data: data,
124 | dataType: 'json',
125 | xhrFields: {
126 | withCredentials: true // 携带跨域cookie
127 | },
128 | crossDomain: true,
129 | beforeSend: function(xhr) {
130 | xhr.setRequestHeader('X-Requested-With','XMLHttpRequest');
131 | },
132 | success: function(res){
133 | setTimeout(function() {
134 | sa.hideLoading();
135 | // 如果相应的处理函数存在
136 | if(cfg['success' + res.code] != undefined) {
137 | return cfg['success' + res.code](res);
138 | }
139 | layer.alert('未知状态码:' + JSON.stringify(res));
140 | }, cfg.sleep);
141 | },
142 | error: function(xhr, type, errorThrown){
143 | setTimeout(function() {
144 | sa.hideLoading();
145 | return cfg.errorfn(xhr, type, errorThrown);
146 | }, cfg.sleep);
147 | },
148 | complete: cfg.complete
149 | });
150 |
151 | };
152 |
153 |
154 |
155 | // 模拟一个ajax
156 | // 请注意: 本模板中所有ajax请求调用的均为此模拟函数
157 | sa.ajax2 = function(url, data, success200, cfg){
158 | // 如果是简写模式(省略了data参数)
159 | if(typeof data === 'function'){
160 | cfg = success200;
161 | success200 = data;
162 | data = {};
163 | }
164 | // 几个默认配置
165 | cfg = cfg || {};
166 | // 设定一个默认的提示文字
167 | if(cfg.msg == undefined || cfg.msg == null || cfg.msg == '') {
168 | cfg.msg = '正在努力加载...';
169 | }
170 | // 默认延时函数
171 | if(cfg.sleep == undefined || cfg.sleep == null || cfg.sleep == '' || cfg.sleep == 0) {
172 | cfg.sleep = 600;
173 | }
174 | // 默认的模拟数据
175 | cfg.res = cfg.res || {
176 | code: 200,
177 | msg: 'ok',
178 | data: []
179 | }
180 | // 开始loding
181 | sa.loading(cfg.msg);
182 | // 模拟ajax的延时
183 | setTimeout(function() {
184 | sa.hideLoading(); // 隐藏掉转圈圈
185 | success200(cfg.res);
186 | }, cfg.sleep)
187 | };
188 |
189 | })();
190 |
191 |
192 | // =========================== 封装弹窗相关函数 =======================================
193 | (function() {
194 |
195 | // ============== 小提示 =====================
196 | var me = sa;
197 | layer.ready(function(){});
198 |
199 | // tips提示文字
200 | me.msg = function(msg, cfg) {
201 | msg = msg || '操作成功';
202 | layer.msg(msg, cfg);
203 | };
204 |
205 | // 操作成功的提示
206 | me.ok = function(msg) {
207 | msg = msg || '操作成功';
208 | layer.msg(msg, {anim: 0, icon: 1 });
209 | }
210 | me.ok2 = function(msg) {
211 | msg = msg || '操作成功';
212 | layer.msg(msg, {anim: 0, icon: 6 });
213 | }
214 |
215 | // 操作失败的提示
216 | me.error = function(msg) {
217 | msg = msg || '操作失败';
218 | layer.msg(msg, {anim: 6, icon: 2 });
219 | }
220 | me.error2 = function(msg) {
221 | msg = msg || '操作失败';
222 | layer.msg(msg, {anim: 6, icon: 5 });
223 | }
224 |
225 | // alert弹窗 [text=提示文字, cfg=配置(可省略), okFn=点击确定之后的回调函数]
226 | me.alert = function(text, okFn) {
227 | // 开始弹窗
228 | layer.alert(text, function(index) {
229 | layer.close(index);
230 | if(okFn) {
231 | okFn();
232 | }
233 | });
234 | };
235 |
236 | // 询问框 [text=提示文字, okFn=点击确定之后的回调函数]
237 | me.confirm = function(text, okFn) {
238 | layer.confirm(text, {}, function(index) {
239 | layer.close(index);
240 | if(okFn) {
241 | okFn();
242 | }
243 | }.bind(this));
244 | };
245 |
246 | // 输入框 [title=提示文字, okFn=点击确定后的回调函数, formType=输入框类型(0=文本,1=密码,2=多行文本域) 可省略, value=默认值 可省略 ]
247 | me.prompt = function(title, okFn, formType, value) {
248 | layer.prompt({
249 | title: title,
250 | formType: formType,
251 | value: value
252 | }, function(pass, index){
253 | layer.close(index);
254 | if(okFn) {
255 | okFn(pass);
256 | }
257 | });
258 | }
259 |
260 | // 打开loading
261 | me.loading = function(msg) {
262 | layer.closeAll(); // 开始前先把所有弹窗关了
263 | return layer.msg(msg, {icon: 16, shade: 0.3, time: 1000 * 20, skin: 'ajax-layer-load' });
264 | };
265 |
266 | // 隐藏loading
267 | me.hideLoading = function() {
268 | layer.closeAll();
269 | };
270 |
271 | // ============== 一些常用弹窗 =====================
272 |
273 | // 大窗显示一个图片
274 | // 参数: src=地址、w=宽度(默认80%)、h=高度(默认80%)
275 | me.showImage = function(src, w, h) {
276 | w = w || '80%';
277 | h = h || '80%';
278 | var content = '' +
279 | '
' +
280 | '
';
281 | layer.open({
282 | type: 1,
283 | title: false,
284 | shadeClose: true,
285 | closeBtn: 0,
286 | area: [w, h], //宽高
287 | content: content
288 | });
289 | }
290 |
291 | // 预览一组图片
292 | // srcList=图片路径数组, index=打开立即显示哪张(可填下标, 也可填写src路径)
293 | me.showImageList = function(srcList, index) {
294 | // 如果填的是个string
295 | if(typeof srcList === 'string') {
296 | try{
297 | srcList = JSON.parse(srcList);
298 | }catch(e){
299 | srcList = [];
300 | }
301 | }
302 | // 如果填的是路径
303 | index = index || 0;
304 | if(typeof index === 'string') {
305 | index = srcList.indexOf(index);
306 | index = (index == -1 ? 0 : index);
307 | }
308 |
309 | // 开始展示
310 | var arr_list = [];
311 | srcList.forEach(function(item) {
312 | arr_list.push({
313 | alt: '左右键切换',
314 | pid: 1,
315 | src: item,
316 | thumb: item
317 | })
318 | })
319 | layer.photos({
320 | photos: {
321 | title: '',
322 | id: new Date().getTime(),
323 | start: index,
324 | data: arr_list
325 | }
326 | ,anim: 5 //0-6的选择,指定弹出图片动画类型,默认随机(请注意,3.0之前的版本用shift参数)
327 | });
328 | }
329 |
330 | // 显示一个iframe
331 | // 参数: 标题,地址,宽,高 , 点击遮罩是否关闭, 默认false
332 | me.showIframe = function(title, url, w, h, shadeClose) {
333 | // 参数修正
334 | w = w || '95%';
335 | h = h || '95%';
336 | shadeClose = (shadeClose === undefined ? false : shadeClose);
337 | // 弹出面板
338 | var index = layer.open({
339 | type: 2,
340 | title: title, // 标题
341 | shadeClose: shadeClose, // 是否点击遮罩关闭
342 | maxmin: true, // 显示最大化按钮
343 | shade: 0.8, // 遮罩透明度
344 | scrollbar: false, // 屏蔽掉外层的滚动条
345 | moveOut: true, // 是否可拖动到外面
346 | area: [w, h], // 大小
347 | content: url, // 传值
348 | // 解决拉伸或者最大化的时候,iframe高度不能自适应的问题
349 | resizing: function(layero) {
350 | solveLayerBug(index);
351 | }
352 | });
353 | // 解决拉伸或者最大化的时候,iframe高度不能自适应的问题
354 | $('#layui-layer' + index + ' .layui-layer-max').click(function() {
355 | setTimeout(function() {
356 | solveLayerBug(index);
357 | }, 200)
358 | })
359 | }
360 | me.showView = me.showIframe;
361 |
362 | // 显示一个iframe, 底部按钮方式
363 | // 参数: 标题,地址,点击确定按钮执行的代码(在子窗口执行),宽,高
364 | me.showIframe2 = function(title, url, evalStr, w, h) {
365 | // 参数修正
366 | w = w || '95%';
367 | h = h || '95%';
368 | // 弹出面板
369 | var index = layer.open({
370 | type: 2,
371 | title: title, // 标题
372 | closeBtn: (title ? 1 : 0), // 是否显示关闭按钮
373 | btn: ['确定', '取消'],
374 | shadeClose: false, // 是否点击遮罩关闭
375 | maxmin: true, // 显示最大化按钮
376 | shade: 0.8, // 遮罩透明度
377 | scrollbar: false, // 屏蔽掉外层的滚动条
378 | moveOut: true, // 是否可拖动到外面
379 | area: [w, h], // 大小
380 | content: url, // 传值
381 | // 解决拉伸或者最大化的时候,iframe高度不能自适应的问题
382 | resizing: function(layero) {
383 |
384 | },
385 | yes: function(index, layero) {
386 | var iframe = document.getElementById('layui-layer-iframe' + index);
387 | var iframeWindow = iframe.contentWindow;
388 | iframeWindow.eval(evalStr);
389 | }
390 | });
391 | }
392 |
393 |
394 | // 当前iframe关闭自身 (在iframe中调用)
395 | me.closeCurrIframe = function() {
396 | try{
397 | var index = parent.layer.getFrameIndex(window.name); //先得到当前iframe层的索引
398 | parent.layer.close(index); //再执行关闭
399 | }catch(e){
400 | //TODO handle the exception
401 | }
402 | }
403 | me.closeCurrView = me.closeCurrIframe;
404 |
405 |
406 | //执行一个函数, 解决layer拉伸或者最大化的时候,iframe高度不能自适应的问题
407 | function solveLayerBug(index) {
408 | var selected = '#layui-layer' + index;
409 | var height = $(selected).height();
410 | var title_height = $(selected).find('.layui-layer-title').height();
411 | $(selected).find('iframe').css('height', (height - title_height) + 'px');
412 | }
413 |
414 |
415 | })();
416 |
417 |
418 | // =========================== 常用util函数封装 =======================================
419 | (function () {
420 |
421 | // 超级对象
422 | var me = sa;
423 |
424 | // =========================== 常用util函数封装 =======================================
425 | if(true) {
426 |
427 | // 从url中查询到指定参数值
428 | me.p = function(name, defaultValue){
429 | var query = window.location.search.substring(1);
430 | var vars = query.split("&");
431 | for (var i=0;i 0 ? cha : 0 - cha);
526 | if(cha < (86400 * 1000)) {
527 | return me.forDate2(d);
528 | }
529 | return me.forDate(d, way);
530 | }
531 |
532 | // 返回时间差, 此格式数组:[x, x, x, 天, 时, 分, 秒]
533 | me.getSJC = function (small_time, big_time) {
534 | var date1 = new Date(small_time); //开始时间
535 | var date2 = new Date(big_time); //结束时间
536 | var date3 = date2.getTime() - date1.getTime(); //时间差秒
537 | //计算出相差天数
538 | var days = Math.floor(date3 / (24 * 3600 * 1000));
539 |
540 | //计算出小时数
541 | var leave1 = date3 % (24 * 3600 * 1000); //计算天数后剩余的毫秒数
542 | var hours = Math.floor(leave1 / (3600 * 1000));
543 |
544 | //计算相差分钟数
545 | var leave2 = leave1 % (3600 * 1000); //计算小时数后剩余的毫秒数
546 | var minutes = Math.floor(leave2 / (60 * 1000));
547 |
548 | //计算相差秒数
549 | var leave3 = leave2 % (60 * 1000); //计算分钟数后剩余的毫秒数
550 | var seconds = Math.round(leave3 / 1000);
551 |
552 | // 返回数组
553 | return [0, 0, 0, days, hours, minutes, seconds];
554 | }
555 |
556 | // 将日期,加上指定天数
557 | me.dateAdd = function(d, n) {
558 | var s = new Date(d).getTime();
559 | s += 86400000 * n;
560 | return new Date(s);
561 | }
562 |
563 | // 转化json,出错返回默认值
564 | me.JSONParse = function(obj, default_obj){
565 | try{
566 | return JSON.parse(obj) || default_obj;
567 | }catch(e){
568 | return default_obj || {};
569 | }
570 | }
571 |
572 | // 截取指定长度字符,默认50
573 | me.maxLength = function (str, length) {
574 | length = length || 50;
575 | if(!str){
576 | return "";
577 | }
578 | return (str.length > length) ? str.substr(0, length) + ' ...' : str;
579 | },
580 |
581 | // 过滤掉标签
582 | me.text = function(str){
583 | if(!str){
584 | return "";
585 | }
586 | return str.replace(/<[^>]+>/g,"");
587 | }
588 |
589 | // 为指定集合的每一项元素添加上is_update属性
590 | me.listAU = function(list){
591 | list.forEach(function(ts){
592 | ts.is_update = false;
593 | })
594 | return list;
595 | }
596 |
597 | // 获得一段文字中所有图片的路径
598 | me.getSrcList = function(str){
599 | try{
600 | var imgReg = /|\/>)/gi; //匹配图片(g表示匹配所有结果i表示区分大小写)
601 | var srcReg = /src=[\'\"]?([^\'\"]*)[\'\"]?/i; //匹配src属性
602 | var arr = str.match(imgReg); // 图片数组
603 | var srcList = [];
604 | for (var i = 0; i < arr.length; i++) {
605 | var src = arr[i].match(srcReg);
606 | srcList.push(src[1]);
607 | }
608 | return srcList;
609 | } catch (e){
610 | return [];
611 | }
612 | }
613 |
614 | // 无精度损失的乘法
615 | me.accMul = function(arg1, arg2) {
616 | var m = 0,
617 | s1 = arg1.toString(),
618 | s2 = arg2.toString(),
619 | t;
620 |
621 | t = s1.split(".");
622 | // 判断有没有小数位,避免出错
623 | if (t[1]) {
624 | m += t[1].length
625 | }
626 |
627 | t = s2.split(".");
628 | if (t[1]) {
629 | m += t[1].length
630 | }
631 |
632 | return Number(s1.replace(".", "")) * Number(s2.replace(".", "")) / Math.pow(10, m)
633 | }
634 |
635 | // 正则验证是否为手机号
636 | me.isPhone = function(str) {
637 | str = str + '';
638 | if((/^1[34578]\d{9}$/.test(str))){
639 | return true;
640 | }
641 | return false;
642 | }
643 |
644 | // 产生随机字符串
645 | me.randomString = function(len) {
646 | len = len || 32;
647 | var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
648 | var maxPos = $chars.length;
649 | var str = '';
650 | for (i = 0; i < len; i++) {
651 | str += $chars.charAt(Math.floor(Math.random() * maxPos));
652 | }
653 | return str;
654 | }
655 |
656 |
657 | // == if 结束
658 | }
659 |
660 | // =========================== 数组操作 =======================================
661 | if (true) {
662 |
663 |
664 | // 从数组里获取数据,根据指定数据
665 | me.arrayGet = function(arr, prop, value){
666 | for (var i = 0; i < arr.length; i++) {
667 | if(arr[i][prop] == value){
668 | return arr[i];
669 | }
670 | }
671 | return null;
672 | }
673 |
674 | // 从数组删除指定记录
675 | me.arrayDelete = function(arr, item){
676 | var index = arr.indexOf(item);
677 | if (index > -1) {
678 | arr.splice(index, 1);
679 | }
680 | }
681 |
682 | // 从数组删除指定id的记录
683 | me.arrayDeleteById = function(arr, id){
684 | var item = me.arrayGet(arr, 'id', id);
685 | me.arrayDelete(arr, item);
686 | }
687 |
688 | // 将数组B添加到数组A的开头
689 | me.unshiftArray = function(arrA, arrB){
690 | if(arrB){
691 | arrB.reverse().forEach(function(ts){
692 | arrA.unshift(ts);
693 | })
694 | }
695 | return arrA;
696 | }
697 |
698 | // 将数组B添加到数组A的末尾
699 | me.pushArray = function(arrA, arrB){
700 | if(arrB){
701 | arrB.forEach(function(ts){
702 | arrA.push(ts);
703 | })
704 | }
705 | return arrA;
706 | }
707 |
708 | // == if 结束
709 | }
710 |
711 | // =========================== 浏览器相关 =======================================
712 | if (true) {
713 |
714 | // set cookie 值
715 | me.setCookie = function setCookie(cname, cvalue, exdays) {
716 | exdays = exdays || 30;
717 | var d = new Date();
718 | d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
719 | var expires = "expires=" + d.toGMTString();
720 | document.cookie = cname + "=" + escape(cvalue) + "; " + expires + "; path=/";
721 | }
722 |
723 | // get cookie 值
724 | me.getCookie = function(objName){
725 | var arrStr = document.cookie.split("; ");
726 | for (var i = 0; i < arrStr.length; i++) {
727 | var temp = arrStr[i].split("=");
728 | if (temp[0] == objName){
729 | return unescape(temp[1])
730 | };
731 | }
732 | return "";
733 | }
734 |
735 | // 复制指定文本
736 | me.copyText = function(str){
737 | var oInput = document.createElement('input');
738 | oInput.value = str;
739 | document.body.appendChild(oInput);
740 | oInput.select(); // 选择对象
741 | document.execCommand("Copy"); // 执行浏览器复制命令
742 | oInput.className = 'oInput';
743 | oInput.style.display='none';
744 | }
745 |
746 | // jquery序列化表单增强版: 排除空值
747 | me.serializeNotNull = function(selected){
748 | var serStr = $(selected).serialize();
749 | return serStr.split("&").filter(function(str){return !str.endsWith("=")}).join("&");
750 | }
751 |
752 | // 将cookie序列化为k=v形式
753 | me.strCookie = function(){
754 | return document.cookie.replace(/; /g,"&");
755 | }
756 |
757 | // 回到顶部
758 | me.goTop = function() {
759 | function smoothscroll(){
760 | var currentScroll = document.documentElement.scrollTop || document.body.scrollTop;
761 | if (currentScroll > 0) {
762 | window.requestAnimationFrame(smoothscroll);
763 | window.scrollTo (0,currentScroll - (currentScroll/5));
764 | }
765 | };
766 | smoothscroll();
767 | }
768 |
769 |
770 |
771 | // == if 结束
772 | }
773 |
774 | // =========================== javascript对象操作 =======================================
775 | if (true) {
776 | // 去除json对象中的空值
777 | me.removeNull = function(obj){
778 | var newObj = {};
779 | if(obj != undefined && obj != null) {
780 | for(var key in obj) {
781 | if(obj[key] === undefined || obj[key] === null || obj[key] == '') {
782 | //
783 | } else {
784 | newObj[key] = obj[key];
785 | }
786 | }
787 | }
788 | return newObj;
789 | }
790 |
791 | // JSON 浅拷贝, 返回拷贝后的obj
792 | me.copyJSON = function(obj){
793 | if(obj === null || obj === undefined) {
794 | return obj;
795 | };
796 | var new_obj = {};
797 | for(var key in obj) {
798 | new_obj[key] = obj [key];
799 | }
800 | return new_obj;
801 | }
802 |
803 | // json合并, 将 defaulet配置项 转移到 user配置项里 并返回 user配置项
804 | me.extendJson = function(userOption, defaultOption) {
805 | if(!userOption) {
806 | return defaultOption;
807 | };
808 | for(var key in defaultOption) {
809 | if(userOption[key] === undefined) {
810 | userOption[key] = defaultOption[key];
811 | } else if(userOption[key] == null){
812 |
813 | } else if(typeof userOption[key] == "object") {
814 | me.extendJson(userOption[key], defaultOption[key]); //深度匹配
815 | }
816 | }
817 | return userOption;
818 | }
819 |
820 | // == if 结束
821 | }
822 |
823 | // =========================== 本地集合存储 =======================================
824 | if (true) {
825 |
826 | // 获取指定key的list
827 | me.keyListGet = function(key){
828 | try{
829 | var str = localStorage.getItem('LIST_' + key);
830 | if(str == undefined || str == null || str =='' || str == 'undefined' || typeof(JSON.parse(str)) == 'string'){
831 | //alert('key' + str);
832 | str = '[]';
833 | }
834 | return JSON.parse(str);
835 | }catch(e){
836 | return [];
837 | }
838 | },
839 |
840 | me.keyListSet = function(key, list){
841 | localStorage.setItem('LIST_' + key, JSON.stringify(list));
842 | },
843 |
844 | me.keyListHas = function(key, item){
845 | var arr2 = me.keyListGet(key);
846 | return arr2.indexOf(item) != -1;
847 | },
848 |
849 | me.keyListAdd = function(key, item){
850 | var arr = me.keyListGet(key);
851 | arr.push(item);
852 | me.keyListSet(key,arr);
853 | },
854 |
855 | me.keyListRemove = function(key, item){
856 | var arr = me.keyListGet(key);
857 | var index = arr.indexOf(item);
858 | if (index > -1) {
859 | arr.splice(index, 1);
860 | }
861 | me.keyListSet(key,arr);
862 | }
863 |
864 | // == if 结束
865 | }
866 |
867 | })();
868 |
869 |
870 | // =========================== $sys 有关当前系统的方法 一般不能复制到别的项目中用 =======================================
871 | (function(){
872 |
873 | // 超级对象
874 | var me = {};
875 | sa.$sys = me;
876 |
877 | // 定义key
878 | var pcode_key = 'permission_code';
879 |
880 | // 写入当前会话的权限码集合
881 | sa.setAuth = function(codeList) {
882 | sa.keyListSet(pcode_key, codeList);
883 | }
884 |
885 | // 清除当前会话的权限码集合
886 | sa.clearAuth = function() {
887 | sa.keyListSet(pcode_key, []);
888 | }
889 |
890 | // 检查当前会话是否拥有一个权限码, 返回true和false
891 | sa.isAuth = function(pcode) {
892 | return sa.keyListHas(pcode_key, pcode);
893 | }
894 |
895 | // 检查当前会话是否拥有一个权限码, 如果没有, 则跳转到无权限页面
896 | // 注意: 非二级目录页面请注意调整路径问题
897 | sa.checkAuth = function(pcode) {
898 | var is_have = sa.keyListHas(pcode_key, pcode);
899 | if(is_have == false) {
900 | Vue.prototype.sa_admin.open403();
901 | throw '暂无权限: ' + pcode;
902 | }
903 | }
904 |
905 |
906 |
907 |
908 |
909 | })();
910 |
911 |
912 | // =========================== $page 跳页面相关 避免一次变动,到处乱改 =======================================
913 | (function(){
914 |
915 | // 超级对象
916 | var me={};
917 | sa.$page = me;
918 |
919 |
920 |
921 | })();
922 |
923 |
924 | // 如果当前是Vue环境, 则挂在到Vue示例
925 | if(window.Vue && !Vue.prototype.sa) {
926 | Vue.prototype.sa = sa;
927 | }
928 |
929 | // 对外开放, 在模块化时解开此注释
930 | export default sa;
931 |
932 |
--------------------------------------------------------------------------------
/src/sa-resources/index/sa-index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import saMenuList from './../sa-menu-list.js'; // 菜单集合
3 | import sa_admin_code_util from './admin-util.js'; // admin代码util
4 | import { swiper, swiperSlide } from 'vue-awesome-swiper'; // 组件 swiper
5 | import saLogin from './../com-view/sa-login.vue'; // 组件 login
6 | import sa403 from './../com-view/sa-403.vue'; // 组件 403
7 | import sa404 from './../com-view/sa-404.vue'; // 组件 404
8 | import sa500 from './../com-view/sa-500.vue'; // 组件 500
9 | // sa_admin对象
10 | export default {
11 | components: {
12 | swiper,
13 | swiperSlide,
14 | saLogin,
15 | sa403,
16 | sa404,
17 | sa500
18 | },
19 | data: function() {
20 | // 首页
21 | var homeTab = {
22 | id: 'home', // 唯一标识
23 | name: '首页',
24 | view: ()=> import('./../com-view/sa-home.vue'),
25 | hide_close: true, // 隐藏关闭键
26 | is_rend: true,
27 | }
28 |
29 | return {
30 | version: 'v1.0.3', // 当前版本
31 | update_time: '2020-03-05', // 更新日期
32 | title: '',//'SA-后台模板', // 页面标题
33 | logo_url: '', // logo地址
34 | icon_url: '', // icon地址
35 | github_url: 'https://github.com/click33/sa-vue-admin', // github地址
36 | default_active: '0', // 默认的高亮菜单id
37 | default_openeds: [], // 默认的打开数组
38 | unique_opened: true, // 是否保持只打开一个
39 | menuList: [], // 菜单集合
40 | homeTab: homeTab, // 主页tab
41 | nativeTab: homeTab, // 当前正显示的Tab
42 | tabList: [homeTab], // 页面集合
43 | atTitle: '', // 添加窗口时: 标题
44 | atUrl: '', // 添加窗口时: 地址
45 | scrollX: 0 ,// 滚动条位置
46 | // rightMaxHeight: 0, // 右键菜单的最高高度 (控制是否展开)
47 | // rightZB: {x: 0, y: 0} ,// 右键菜单坐标
48 | rightTab: null, // 右键正在操作的tab
49 | rightShow: false, // 右键菜单是否正在显示
50 | rightStyle: { // 卡片标题右键菜单的样式
51 | left: '0px', // 坐标x
52 | top: '0px', // 坐标y
53 | maxHeight: '0px' // 右键菜单的最高高度 (控制是否展开)
54 | },
55 | is_drag: false, // 当前是否正在拖拽
56 | dragTab: null, // 当前正在拖拽的tab
57 | is_fold: false, // 菜单是否折叠
58 | is_fold_right: false, // 右边是否折叠(将右边盒子折叠与菜单折叠分开,这样可以减少动画的卡顿现象)
59 | is_full_screen: false ,// 是否全屏
60 | user: null ,// user信息
61 | now_time: '加载中...' ,// 当前时间
62 | switchV: localStorage.getItem('switchV') || 'fade', // 切换效果
63 | switchList: [ // 切换动画数组
64 | {name: '淡入', value: 'fade'},
65 | {name: '滑动', value: 'slide'},
66 | {name: '方块', value: 'cube'},
67 | {name: '3D流', value: 'coverflow'},
68 | {name: '3D翻转', value: 'flip'}
69 | ],
70 | themeV: localStorage.getItem('themeV') || '1', // 当前主题值
71 | themeList: [ // 主题数组
72 | {name: '蓝色', value: '1', show_all: false},
73 | {name: '绿色', value: '2', show_all: false},
74 | {name: '白色', value: '3', show_all: false},
75 | {name: '灰色', value: '4', show_all: false},
76 | {name: '灰色-展开', value: '5', show_all: true},
77 | {name: 'pro钛合金', value: '6', show_all: false},
78 | {name: '沉淀式黑蓝', value: '7', show_all: false},
79 | {name: '简约式灰蓝', value: '8', show_all: false},
80 | ],
81 | themeToggling: false, // 主题是否正在切换
82 | dropList: [], // 头像处下拉列表菜单
83 | mySwiper: null, // swiper相关
84 | is_show_tabbar: true, // 是否显示tab栏
85 | breMenuList: [homeTab], // 面包屑导航栏的tab数据
86 | is_reme_open: true, // 是否记住上一次最后打开的窗口
87 | // swiper配置
88 | swiperOption:{
89 | autoplay: false, // 自动切换
90 | effect: localStorage.getItem('switchV') || 'fade', // 切换效果
91 | },
92 | dialogTab: null ,// dialogTab信息
93 | }
94 | },
95 | watch: {
96 | // 监听全屏动作
97 | is_full_screen: function(newValue) {
98 | if(newValue) {
99 | sa_admin_code_util.fullScreen();
100 | } else {
101 | sa_admin_code_util.fullScreenNormal();
102 | }
103 | },
104 | // 监听title改变时, 页面title也跟着切换
105 | title: function(newValue) {
106 | document.querySelector('title').innerHTML = newValue;
107 | },
108 | // 监听 icon_url 网页图标
109 | icon_url: function(newValue) {
110 | var icon_url = newValue;
111 | var icon_target = document.querySelector('.admin-icon');
112 | if(icon_target) {
113 | icon_target.setAttribute('href', icon_url);
114 | }
115 | }
116 | },
117 | computed: {
118 | },
119 | methods: {
120 | // ------------------- 初始化相关 --------------------
121 | // 初始化模板, 此方法只可调用一次
122 | init: function(option) {
123 | // 如果不填写
124 | option = option || {};
125 |
126 | // 一些属性
127 | this.is_show_tabbar = (option.is_show_tabbar === undefined ? this.is_show_tabbar : option.is_show_tabbar); // 是否显示tabbar栏
128 | this.is_reme_open = (option.is_reme_open === undefined ? this.is_reme_open : option.is_reme_open); // 是否记住上一次最后打开的窗口
129 |
130 | // 初始化swiper对象
131 | this.initSwiper();
132 |
133 | // 打印版本等信息
134 | if(option.printVesion !== false) {
135 | this.printVesion();
136 | }
137 |
138 | // 开始一些初始化动作
139 | this.showTabByHash(); // 打开上次最后的一个窗口
140 | window.onresize(); // 手动触发一下窗口变动监听
141 | },
142 | // ------------------- 对外预留接口 --------------------
143 | // show_list 为指定显示的id集合(注意是id的集合),为空时代表显示所有
144 | initMenu: function(show_list) {
145 | this.setMenuList(saMenuList, show_list);
146 | },
147 | // 写入菜单,可以是一个一维数组(指定好parent_id),也可以是一个已经渲染好的tree数组
148 | // show_list 为指定显示的id集合(注意是id的集合),为空时代表显示所有
149 | setMenuList: function(menu_list, show_list) {
150 | // 转化为string 便于比较
151 | if(show_list) {
152 | for (var i = 0; i < show_list.length; i++) {
153 | show_list[i] = show_list[i] + '';
154 | }
155 | }
156 | menu_list = this.arrayToTree(menu_list);
157 | menu_list = this.refMenuList(menu_list, show_list);
158 | this.menuList = menu_list;
159 | },
160 | // 将一维平面数组转换为 Tree 菜单 (根据其指定的parent_id添加到其父菜单的childList)
161 | arrayToTree: function(menu_list) {
162 | for (var i = 0; i < menu_list.length; i++) {
163 | var menu = menu_list[i];
164 | // 添加到其指定的父菜单的childList
165 | if(menu.parent_id) {
166 | var parent_menu = this.getMenuById(menu_list, menu.parent_id);
167 | if(parent_menu) {
168 | parent_menu.childList = parent_menu.childList || [];
169 | parent_menu.childList.push(menu);
170 | menu_list.splice(i, 1); // 从一维中删除
171 | i--;
172 | }
173 | }
174 | }
175 | return menu_list;
176 | },
177 | // 将 menu_list 处理一下
178 | refMenuList: function(menu_list, show_list, parent_id) {
179 | for (var i = 0; i < menu_list.length; i++) {
180 | var menu = menu_list[i];
181 | menu.is_show = (menu.is_show === false ? false : true);
182 | menu.parent_id = menu.parent_id || parent_id || 0;
183 | // 隐藏的给去掉
184 | // if(menu.is_show === false) {
185 | // sa_admin_code_util.arrayDelete(menu_list, menu);
186 | // i--;
187 | // continue;
188 | // }
189 | // 如果指定了 show_list,并且 menu.id 不在 show_list 里,划掉
190 | if(show_list && show_list.indexOf(menu.id) == -1) {
191 | // sa_admin_code_util.arrayDelete(menu_list, menu);
192 | // i--;
193 | // continue;
194 | menu.is_show = false;
195 | }
196 | // 有子项的递归处理
197 | if(menu.childList && menu.childList.length > 0){
198 | this.refMenuList(menu.childList, show_list, menu.id); // 递归处理
199 | }
200 | }
201 | return menu_list;
202 | },
203 |
204 | // ------------------- 对外预留 end --------------------
205 | // 打开所有菜单的折叠
206 | show_all_menu: function() {
207 | var default_openeds = [];
208 | for (var i = 0; i < this.menuList.length; i++) {
209 | default_openeds.push(this.menuList[i].id);
210 | if(this.menuList[i].childList) {
211 | for (var j = 0; j < this.menuList[i].childList.length; j++) {
212 | default_openeds.push(this.menuList[i].childList[j].id);
213 | }
214 | }
215 | }
216 | this.default_openeds = default_openeds;
217 | },
218 | // 切换主题
219 | toggleTheme: function(command) {
220 | // 调整动画,避免卡顿
221 | this.themeToggling = true;
222 | setTimeout(function() {
223 | this.themeToggling = false;
224 | }.bind(this), 1000);
225 |
226 | // 开始切换
227 | this.themeV = command + "";
228 | localStorage.setItem('themeV', command);
229 | for (var i = 0; i < this.themeList.length; i++) {
230 | if(this.themeList[i].value + '' == command + '') {
231 | if(this.themeList[i].show_all) {
232 | this.show_all_menu();
233 | this.unique_opened = false;
234 | } else {
235 | this.default_openeds = [];
236 | this.unique_opened = true;
237 | }
238 | // 给个提示
239 | if(window.dsadasdwdwawd) {
240 | this.$message('切换成功,' + this.themeList[i].name);
241 | }
242 | window.dsadasdwdwawd = true;
243 | }
244 | }
245 | },
246 | // 切换翻页方式
247 | toggleSwitch: function(command) {
248 | this.switchV = command + "";
249 | localStorage.setItem('switchV', command);
250 |
251 | this.$confirm('此动画效果将在您刷新页面之后生效,是否立即刷新?', {
252 | confirmButtonText: '确定',
253 | cancelButtonText: '取消',
254 | type: 'warning'
255 | }).then(function() {
256 | location.reload();
257 | }).catch(function() {
258 |
259 | });
260 |
261 | },
262 | // 处理userinfo的下拉点击
263 | handleCommand: function(command) {
264 | this.dropList.forEach(function(drop) {
265 | if(drop.name == command) {
266 | drop.click();
267 | }
268 | })
269 | },
270 | // 退出登录
271 | login_out: function() {
272 | console.log('退出登录');
273 | },
274 | // 折叠菜单
275 | fold_start: function() {
276 | this.is_fold_right = true;
277 | this.updateSlideSize(100); // swipre重新计算大小
278 | // 如果打开的 iframe 在五个以内 浏览器压力很小 就立刻展开菜单,
279 | // 如果打开 iframe 超过5个,浏览器就比较有压力, 此时会卡顿短暂时间,此时延时折叠菜单,让动画显得没那么卡
280 | if(this.tabList.length <= 5) {
281 | this.is_fold = true;
282 | } else {
283 | setTimeout(function() {
284 | this.is_fold = true;
285 | }.bind(this), 100);
286 | }
287 | },
288 | // 展开菜单
289 | fold_end: function() {
290 | this.is_fold = false;
291 | // 延时200ms执行,让它没那么卡
292 | setTimeout(function() {
293 | this.is_fold_right = false;
294 | this.updateSlideSize(); // swipre重新计算大小
295 | }.bind(this), 200);
296 | },
297 | // 刷新一下面包屑导航栏
298 | f5_breMenuList: function() {
299 | // 如果非单窗口模式, 则不刷新了, 节省cpu
300 | if(this.is_show_tabbar) {
301 | return;
302 | }
303 | //
304 | var menu = this.getMenuById(this.menuList, this.nativeTab.id);
305 | if(menu == null) { // 自定义tab这里会取不到值, 就造个假tab就好了
306 | this.breMenuList = [{name: this.nativeTab.name}];
307 | } else {
308 | var breMenuList = [menu];
309 | for (var i = 0; i < breMenuList.length; i+=0) {
310 | var parent_id = breMenuList[0].parent_id;
311 | if(parent_id == 0 || parent_id == undefined) {
312 | break;
313 | }
314 | let menu = this.getMenuById(this.menuList, parent_id);
315 | breMenuList.unshift(menu);
316 | }
317 | this.breMenuList = breMenuList;
318 | }
319 | },
320 | // ------------------- tab 右键菜单相关 --------------------
321 | // 显示右键菜单
322 | right_showMenu: function(tab, event) {
323 | this.rightTab = tab; // 绑定操作tab
324 | var e = event || window.event;
325 | this.rightStyle.left = (e.clientX + 1) + 'px'; // 设置给坐标x
326 | this.rightStyle.top = e.clientY + 'px'; // 设置给坐标y
327 | this.rightShow = true; // 显示右键菜单
328 | this.$nextTick(function() {
329 | var foxHeight = document.querySelector('.right-box-2').offsetHeight; // 应该展开多高
330 | this.rightStyle.maxHeight = foxHeight + 'px'; // 展开
331 | document.querySelector('.right-box').focus(); // 获得焦点,以被捕获失去焦点事件
332 | });
333 | },
334 | // 关闭右键菜单 - 立即关闭
335 | right_closeMenu: function() {
336 | this.rightStyle.maxHeight = '0px';
337 | this.rightShow = false;
338 | },
339 | // 关闭右键菜单 - 带动画折叠关闭 (失去焦点和点击取消时调用, 为什么不全部调用这个? 因为其它时候调用这个都太卡了)
340 | right_closeMenu2: function() {
341 | this.rightStyle.maxHeight = '0px';
342 | // this.rightShow = false;
343 | },
344 | // 右键 刷新
345 | right_f5: function() {
346 | this.showTab(this.rightTab); // 先转到
347 | this.rightTab.is_rend = false;
348 | this.$forceUpdate(); // 必须强制更新一下
349 | this.$nextTick(function() {
350 | this.rightTab.is_rend = true;
351 | })
352 |
353 | },
354 | // 右键 复制
355 | right_copy: function() {
356 | var tab = {id: new Date().getTime(), name: this.rightTab.name, view: this.rightTab.view};
357 | this.showTab(tab);
358 | },
359 | // 右键 悬浮
360 | right_xf: function() {
361 | if(this.rightTab.id == this.homeTab.id + ''){
362 | this.$message({
363 | message: '这个不能全屏哦,换个卡片试试吧',
364 | type: 'warning'
365 | });
366 | return;
367 | }
368 | // 先关闭
369 | this.closeTab(this.rightTab, function() {
370 | this.f5_breMenuList();
371 | }.bind(this));
372 | // 再打开
373 | this.dialogTabShow(this.rightTab.name, this.rightTab.view, this.rightTab.params, 2);
374 | },
375 | // 右键 - 关闭
376 | right_close: function() {
377 | if(this.rightTab.id == this.homeTab.id + ''){
378 | this.$message({
379 | message: '这个不能关闭哦',
380 | type: 'warning'
381 | });
382 | return; // 隐藏右菜单
383 | }
384 | this.closeTab(this.rightTab, function() {
385 | this.f5_breMenuList();
386 | }.bind(this));
387 | },
388 | // 右键 - 关闭其它
389 | right_close_other: function() {
390 | // 先滑到最左边
391 | this.scrollX = 0;
392 | // 递归删除
393 | var i = 0;
394 | var deleteFn = function() {
395 | // 如果已经遍历全部
396 | if(i >= this.tabList.length) {
397 | return;
398 | }
399 | // 如果在白名单,i++继续遍历, 如果不是,递归删除
400 | var tab = this.tabList[i];
401 | if(tab.id + '' == this.homeTab.id + '' || tab.id + '' == this.rightTab.id){
402 | i++;
403 | deleteFn();
404 | } else {
405 | this.closeTab(tab, function() {
406 | deleteFn();
407 | });
408 | }
409 | }.bind(this);
410 | deleteFn();
411 | },
412 | // 右键 - 关闭所有
413 | right_close_all: function() {
414 | // 先滑到最左边
415 | this.scrollX = 0;
416 | // 递归删除
417 | var i = 0;
418 | var deleteFn = function() {
419 | // 如果已经遍历全部
420 | if(i >= this.tabList.length) {
421 | this.f5_breMenuList();
422 | return;
423 | }
424 | // 如果在白名单,i++继续遍历, 如果不是,递归删除
425 | var tab = this.tabList[i];
426 | if(tab.id + '' == this.homeTab.id + ''){
427 | i++;
428 | deleteFn();
429 | } else {
430 | this.closeTab(tab, function() {
431 | deleteFn();
432 | });
433 | }
434 | }.bind(this);
435 | deleteFn();
436 | },
437 | // 右键 - 全屏打开
438 | right_full: function() {
439 | // 先关闭
440 | if(this.rightTab.id != this.homeTab.id + ''){ // 主页就不关了
441 | this.closeTab(this.rightTab, function() {
442 | this.f5_breMenuList();
443 | }.bind(this));
444 | }
445 | // 再打开
446 | this.dialogTabShow(this.rightTab.name, this.rightTab.view, this.rightTab.params, 1);
447 | },
448 | // 右键 - 新窗口打开
449 | right_window_open: function() {
450 | // 先关闭
451 | if(this.rightTab.id != this.homeTab.id + ''){ // 主页就不关了
452 | this.closeTab(this.rightTab, function() {
453 | this.f5_breMenuList();
454 | }.bind(this));
455 | }
456 | open(this.rightTab.url);
457 | },
458 | // 获取指定tab所代表iframe的url地址 (同域下可获取最新地址, 跨域时只能获取初始化时的地址)
459 | getTabUrl: function(tab) {
460 | this.sss(tab);
461 | // var cs = '#iframe-' + tab.id;
462 | // var iframe = document.querySelector(cs);
463 | // try{
464 | // return iframe.contentWindow.location.href;
465 | // }catch(e){
466 | // return iframe.getAttribute('src');
467 | // }
468 | },
469 |
470 | // ------------------- menu 相关 --------------------
471 | // 点击子菜单时的回调,
472 | // 参数: 点击菜单index标识(不是下标), 所有已经打开的菜单 index
473 | selectMenu: function(index) {
474 | var menu = this.getMenuById(this.menuList, index);
475 | if(menu != null) {
476 | // 如果是click函数
477 | if(menu.click) {
478 | return menu.click(this, this.sa);
479 | }
480 | // 如果是外部链接
481 | if(menu.is_blank) {
482 | return open(menu.url);
483 | }
484 | this.showTab(menu);
485 | }
486 | },
487 | // js显示某个菜单
488 | showMenuById: function(id) {
489 | var menu = this.getMenuById(this.menuList, id);
490 | if(menu) {
491 | this.showTab(menu);
492 | }
493 | },
494 | // 返回指定 index 的menu
495 | getMenuById: function(menuList, id) {
496 | for (var i = 0; i < menuList.length; i++) {
497 | var menu = menuList[i];
498 | if(menu.id + '' == id + '') {
499 | return menu;
500 | }
501 | // 如果是二级或多级
502 | if(menu.childList) {
503 | var menu2 = this.getMenuById(menu.childList, id);
504 | if(menu2 != null) {
505 | return menu2;
506 | }
507 | }
508 | }
509 | return null;
510 | },
511 | // 显示homeTab
512 | showHome: function() {
513 | this.showTab(this.homeTab);
514 | },
515 |
516 | // ------------------- tab title 相关 --------------------
517 | // 在一个tab上, 初始化 view
518 | initTabView: function(tab) {
519 | // 如果已经初始化过了
520 | if(tab.is_init_view) {
521 | return;
522 | }
523 | // 开始初始化
524 | tab.params = tab.params || {}; // 给参数一个默认值
525 | tab.is_rend = true; // 是否显示, 利用此来强制刷新子组件
526 |
527 | // 如果是一个.html页面
528 | if(tab.url) {
529 | let template = '
';
530 | tab.view = {template: template};
531 | return tab.is_init_view = true;
532 | }
533 |
534 | // 如果是
535 |
536 | return tab.is_init_view = true;
537 | },
538 | // 关闭tab - 无动画版本
539 | closeTab_not_an: function(tab) {
540 | this.sss(tab);
541 | // 根据没有地方调用这个方法, 所以先不写了嘻嘻
542 | },
543 | // 关闭页面
544 | closeTab: function(tab, callFn) {
545 |
546 | // 执行关闭动画
547 | var div = document.querySelector('#tab-' + tab.id);
548 | div.style.width = div.offsetWidth + 'px';
549 | setTimeout(function() {
550 | div.style.width = '0px';
551 | }, 0);
552 |
553 | // 等待动画结束
554 | setTimeout(function() {
555 |
556 | // 如果tab为当前正在显示的tab, 则先不让它显示
557 | if(tab == this.nativeTab) {
558 | var index = this.tabList.indexOf(tab);
559 | var preTab = this.tabList[index - 1];
560 | this.showTab(preTab);
561 | }
562 | // 开始从集合中移除
563 | sa_admin_code_util.arrayDelete(this.tabList, tab);
564 | // this.deleteSlide(tab.id);
565 | // 如果有回调
566 | if(callFn) {
567 | this.$nextTick(function() {
568 | callFn();
569 | })
570 | }
571 | }.bind(this), 150);
572 | },
573 | // js关闭某个tab, 根据id
574 | closeTabById: function(id, callFn) {
575 | var tab = this.getTabById(id);
576 | if(tab) {
577 | this.closeTab(tab, callFn);
578 | }
579 | },
580 | // 添加一个Tab {id,name,url}
581 | addTab: function(tab) {
582 | tab.is_have_en = this.is_have_en(tab.name); // 有英文字母的不能加字体加粗动画, 因为会影响tab选项卡的width尺寸, 造成动画混乱
583 | // tab.view = () => import('@/sa-view/HelloWorld.vue');
584 | this.initTabView(tab);
585 | this.tabList.push(tab);
586 | // this.addSlide(tab);
587 | },
588 | // 显示某个页面 (如果不存在, 则先添加)
589 | showTab: function(tab) {
590 | // 如果是当前正在显示的tab , 则直接 返回
591 | if(tab == this.nativeTab && tab != this.homeTab) {
592 | return;
593 | }
594 | // 如果没有先添加
595 | if(this.getTabById(tab.id) == null){
596 | this.addTab(tab);
597 | }
598 | // 然后显示
599 | this.$nextTick(function() {
600 |
601 | this.gotoSlide(tab.id);
602 | // 如果是无tabbar模式
603 | if(!this.is_show_tabbar) {
604 | this.rightTab = tab;
605 | this.right_close_other();
606 | this.f5_breMenuList();
607 | }
608 | this.f5HashByNativeTab();
609 | })
610 |
611 | this.nativeTab = tab;
612 | this.default_active = tab.id + ''; // 左边自动关联, 如果左边没有,则无效果
613 |
614 | // 归位一下
615 | this.$nextTick(function() {
616 | this.scrollToAuto();
617 | }.bind(this))
618 | },
619 | // 显示一个选项卡, 根据 id , 不存在则不显示
620 | showTabById: function(id) {
621 | var tab = this.getTabById(id);
622 | if(tab) {
623 | this.showTab(tab);
624 | }
625 | },
626 | // 获取 Tab 根据 id
627 | getTabById: function(id) {
628 | for (var i = 0; i < this.tabList.length; i++) {
629 | if(this.tabList[i].id + '' == id + '') {
630 | return this.tabList[i];
631 | }
632 | }
633 | return null;
634 | },
635 | // 双击tab栏空白处, 打开弹窗添加窗口
636 | atOpen: function() {
637 | window.r_layer_12345 = this.layer.open({
638 | type: 1,
639 | shade: 0.5,
640 | title: "添加新窗口", //不显示标题
641 | content: $('.at-form-dom'), //捕获的元素
642 | cancel: function(){
643 |
644 | }
645 | });
646 | },
647 | // 根据表单添加新窗口
648 | atOk: function() {
649 | if(this.atTitle == '' || this.atUrl == '') {
650 | return;
651 | }
652 | // 创建tab
653 | var tab = {id: new Date().getTime(), name: this.atTitle, url: this.atUrl};
654 | // 打开tab
655 | this.showTab(tab);
656 | // 关闭并清空
657 | this.layer.close(window.r_layer_12345);
658 | this.atTitle = '';
659 | this.atUrl = '';
660 | },
661 | // 返回一个字符串中是否有英文字母
662 | is_have_en: function(str) {
663 | var reg = /[a-z]/i;
664 | return reg.test(str);//true,说明有英文字母
665 | },
666 | // ------------------- tab左右滑动 --------------------
667 | // 视角向左滑动一段距离
668 | scrollToLeft: function() {
669 | var width = document.querySelector('.nav-right-2').clientWidth; // 视角宽度
670 | this.scrollX += width / 2; // 视角向左滑动一段距离
671 | // 越界检查
672 | setTimeout(function() {
673 | if(this.scrollX > 0){
674 | this.scrollX = 0;
675 | }
676 | }.bind(this), 200);
677 | },
678 | // 视角向右滑动一段距离
679 | scrollToRight: function() {
680 | var width = document.querySelector('.nav-right-2').clientWidth; // 视角宽度
681 | var tabListWidth = document.querySelector('.tab-title-box').clientWidth; // title总盒子宽度
682 | var rightLimit = (0 - tabListWidth + width / 2); // 右滑的极限
683 | this.scrollX -= width / 2; // 视角向右滑动一段距离
684 | // 越界检查
685 | setTimeout(function() {
686 | if(this.scrollX < rightLimit){
687 | this.scrollX = rightLimit;
688 | }
689 | // 同时防止左边越界
690 | if(this.scrollX > 0){
691 | this.scrollX = 0;
692 | }
693 | }.bind(this), 200);
694 | },
695 | // 自动归位
696 | scrollToAuto: function() {
697 | // console.log('自动归位=========');
698 | try{
699 | // 最后一个不用归位了
700 | // if(this.nativeTab == this.tabList[this.tabList.length - 1]){
701 | // return;
702 | // }
703 | var width = document.querySelector('.nav-right-2').clientWidth; // 视角宽度
704 | var left = document.querySelector('.tab-native').lastChild.offsetLeft; // 当前native-tilte下一个距离左边的距离
705 | // console.log(width, left, this.scrollX);
706 | // 如果在视图右边越界
707 | if(left + this.scrollX > (width - 100)){
708 | return this.scrollToRight();
709 | }
710 | // 如果在视图左边越界
711 | if(left + this.scrollX < 0) {
712 | return this.scrollToLeft();
713 | }
714 | }catch(e){
715 | // throw e;
716 | }
717 | },
718 | // ------------------- tab拖拽相关 --------------------
719 | // 在 某个tab上被松开 --> 重新排序 ( 函数未完成 )
720 | tab_ondrop: function(tab) {
721 | this.sss(tab);
722 | /**
723 | * 写到一半发现,这看似简单的一个功能, 实则复杂无比
724 | * 首先tab卡交换顺序, 算法就已经比较复杂, 同时为了不显着生硬,还要加上:
725 | * tab被悬浮提示,
726 | * tab卡交换动画,
727 | * 避开在v-for下操作dom带来的一系列坑
728 | * 其次, 下面的iframe, 也要按照相应顺序进行交换,
729 | * 而swiper本身没有提供这样的api, 又要用js操作dom
730 | * 交换dom顺序, 同时又要保持iframe不被销毁(因为用户肯定不想看到交换一下tab 页面竟然初始化了)
731 | * 同时一些列操作后, 又要保证不和swiper本身产生冲突...
732 | * 脑供血不足了...... 让我缓缓...
733 | * 求前端大神提交pr, 跪谢!!!
734 | */
735 |
736 | // // 如果没有交换
737 | // if(tab == this.dragTab) {
738 | // return;
739 | // }
740 | // // 删除这个
741 | // var dragIndex = this.tabList.indexOf(this.dragTab);
742 | // this.tabList.splice(dragIndex, 1);
743 | // // 重新添加到这个位置
744 | // this.$nextTick(function() {
745 | // var tabIndex = this.tabList.indexOf(tab);
746 | // this.tabList.splice(tabIndex + 1, 0, this.dragTab);
747 | // })
748 | },
749 | // ------------------- 锚链接路由相关 --------------------
750 | // 根据锚链接, 打开窗口
751 | showTabByHash: function() {
752 |
753 | // 如果非记住模式
754 | if(this.is_reme_open == false) {
755 | return;
756 | }
757 | // 获取锚链接中的id
758 | var hash = location.hash;
759 | var id = hash.replace('#', '');
760 |
761 | if(id == '') {
762 | this.showHome();
763 | return;
764 | }
765 | // 如果已经存在与tabbar中
766 | var tab = this.getTabById(id);
767 | if(tab != null) {
768 | return this.showTab(tab);
769 | }
770 | // 否则从菜单中打开
771 | if(id == this.homeTab.id){
772 | this.showHome();
773 | } else {
774 | this.showMenuById(id);
775 | }
776 | // 此时, 仍有一种tab打不开, 那就是自定义tab然后还已经关闭的,
777 | // 预设 解决方案: 在localStor里存储所有打开过的tab,
778 | // 以后如果有强需求这个功能时, 再实现
779 | },
780 | // 根据当前tab刷新一下锚链接
781 | f5HashByNativeTab: function() {
782 | // 如果非记住模式
783 | if(this.is_reme_open == false) {
784 | return;
785 | }
786 | location.hash = this.nativeTab.id;
787 | },
788 | // ------------------- swiper相关 --------------------
789 | // 初始化swiper
790 | initSwiper: function(switchV) {
791 | this.sss(switchV);
792 | this.mySwiper = this.$refs.mySwiper.swiper;
793 | // this.mySwiper = new Swiper('.swiper-container', {
794 | // autoplay: false, // 可选选项,自动滑动
795 | // effect: switchV
796 | // })
797 | },
798 | // 获取指定slide的索引, 根据id
799 | getSlideIndexById: function(id) {
800 | var tab = this.getTabById(id);
801 | return this.tabList.indexOf(tab);
802 | },
803 | // 删除slide, 根据指定iframe的id
804 | deleteSlide: function(id) {
805 | this.sss(id);
806 | // var slideIndex = this.getSlideIndexById(id);
807 | // if(slideIndex != -1) {
808 | // this.mySwiper.removeSlide(slideIndex);
809 | // }
810 | },
811 | // 切换到指定的slide, 根据id
812 | gotoSlide: function(id) {
813 | var slideIndex = this.getSlideIndexById(id);
814 | if(slideIndex != -1) {
815 | this.mySwiper.slideTo(slideIndex, 300);
816 | }
817 | },
818 | // 更正slide大小 ms = 延时毫秒数
819 | updateSlideSize: function(ms) {
820 | ms = ms || 1;
821 | setTimeout(function() {
822 | this.mySwiper.update(); // swipre重新计算大小
823 | }.bind(this), ms);
824 | },
825 | // ------------------- 登录 与鉴权 --------------------
826 | // 打开登录页面
827 | openLogin: function() {
828 | this.$refs['sa-login'].isShow = true;
829 | },
830 | // 关闭login页面
831 | closeLogin: function() {
832 | this.$refs['sa-login'].isShow = false;
833 | },
834 | // 打开403页面
835 | open403: function() {
836 | this.$refs['sa403'].isShow = true;
837 | },
838 | // 打开404页面
839 | open404: function() {
840 | this.$refs['sa404'].isShow = true;
841 | },
842 | // 打开500页面
843 | open500: function() {
844 | this.$refs['sa500'].isShow = true;
845 | },
846 |
847 | // ------------------- 杂七杂八 --------------------
848 | // 什么也不做, 帮助一下不太规范的语法逃避检查
849 | sss: function() {
850 |
851 | },
852 | // 获取指定视图的对象,用来跨视图通信
853 | getView: function(id) {
854 | var com = this.$refs['view-' + id];
855 | if(com) {
856 | return com[0];
857 | }
858 | },
859 | // 悬浮或者, 全屏显示tab
860 | // title=标题, view=要显示的组件, params=参数 ,way= 方式(1=全屏,2=悬浮打开)
861 | dialogTabShow: function(title, view, params, way) {
862 | this.dialogTab = { // dialog信息
863 | isShow: true, // 是否显示
864 | isShow2: true, // 是否显示视图(先关闭视图,在关闭dialog,解决dialog关闭时视图重复刷新的莫名bug)
865 | title: title || '信息', // 标题
866 | view: view || {template: '加载中
'}, // 显示的组件
867 | params: params || {}, // 参数
868 | way: way || 1,
869 | beforeClose: function(done) {
870 | this.dialogTab.isShow2 = false;
871 | done();
872 | }.bind(this)
873 | };
874 | },
875 | closeDialog: function() {
876 | this.dialogTab.isShow = false;
877 | },
878 | // 打开便签
879 | openNote: function() {
880 | var w = (document.body.clientWidth * 0.4) + 'px';
881 | var h = (document.body.clientHeight * 0.6) + 'px';
882 | var default_content = '一个简单的小便签, 关闭浏览器后再次打开仍然可以加载到上一次的记录, 你可以用它来记录一些临时资料';
883 | var value = localStorage.getItem('sa_admin_note') || default_content;
884 | var index = this.layer.prompt({
885 | title: '一个小便签',
886 | value: value,
887 | formType: 2,
888 | area: [w, h],
889 | btn: ['保存'],
890 | maxlength: 99999999,
891 | }, function(pass, index){
892 | this.layer.close(index)
893 | }.bind(this));
894 | var se = '#layui-layer' + index + ' .layui-layer-input';
895 | var d = document.querySelector(se);
896 | d.oninput = function() {
897 | localStorage.setItem('sa_admin_note', this.value);
898 | }
899 | },
900 | // 弹窗
901 | msg: function(msg) {
902 | this.layer.msg(msg)
903 | },
904 | // 打印版本
905 | printVesion: function() {
906 | console.log('欢迎使用sa-admin(vue单页版),当前版本:' + this.version + ",更新于:" + this.update_time + ",GitHub地址:" + this.github_url);
907 | console.log('如在使用中发现任何bug或者疑问,请加入QQ群交流:782974737,点击加入:' + 'https://jq.qq.com/?_wv=1027&k=5DHN5Ib');
908 | },
909 | // 初始化window相关配置
910 | initWindow: function() {
911 |
912 | // sa-admin对象
913 | var sa_admin = this;
914 |
915 | // 挂在到原型
916 | Vue.prototype.sa_admin = sa_admin;
917 |
918 | // 监听窗口大小变动
919 | window.onresize = function() {
920 | if(document.body.clientWidth < 800) {
921 | sa_admin.fold_start();
922 | } else {
923 | sa_admin.fold_end();
924 | }
925 | }
926 |
927 | // 监听锚链接变动
928 | window.onhashchange = function() {
929 | // console.log('锚链接变动了');
930 | this.showTabByHash();
931 | }.bind(this)
932 |
933 | // 一直更新时间
934 | if(window.abcdefghijklmn) {
935 | clearInterval(window.abcdefghijklmn);
936 | }
937 | window.abcdefghijklmn = setInterval(function() {
938 | var da = new Date();
939 | var Y = da.getFullYear(); //年
940 | var M = da.getMonth() + 1; //月
941 | var D = da.getDate(); //日
942 | var h = da.getHours(); //小时
943 | var sx = "凌晨";
944 | if (h >= 6) {
945 | sx = "上午"
946 | }
947 | if (h >= 12) {
948 | sx = "下午";
949 | if (h >= 18) {
950 | sx = "晚上";
951 | }
952 | h -= 12;
953 | }
954 | var m = da.getMinutes(); //分
955 | var s = da.getSeconds(); //秒
956 | var z = ['日', '一', '二', '三', '四', '五', '六'][da.getDay()] ; //周几
957 | // z = z == 0 ? '日' : z;
958 | var zong = "";
959 |
960 | zong += Y + "-" + M + "-" + D + " " + sx + " " + h + ":" + m + ":" + s + " 周" + z;
961 | sa_admin.now_time = zong;
962 | }, 1000);
963 |
964 | }
965 | },
966 | mounted: function(){
967 | this.initWindow();
968 | this.SaAdminInIt(this.sa_admin, this.sa);
969 | },
970 |
971 | };
972 |
973 |
974 |
975 |
976 |
--------------------------------------------------------------------------------