├── tcis ├── __init__.py ├── wsgi.py └── urls.py ├── project_ci ├── __init__.py ├── migrations │ └── __init__.py ├── tests.py ├── admin │ └── __init__.py ├── models │ └── __init__.py ├── signals │ └── __init__.py ├── views │ └── __init__.py ├── permissions │ └── __init__.py ├── serializers │ └── __init__.py ├── apps.py └── urls.py ├── tcis_server ├── __init__.py ├── migrations │ └── __init__.py ├── tests.py ├── admin │ └── __init__.py ├── models │ ├── __init__.py │ └── server.py ├── views │ └── __init__.py ├── permissions │ └── __init__.py ├── serializers │ └── __init__.py ├── signals │ └── __init__.py └── apps.py ├── project ├── migrations │ ├── __init__.py │ ├── 0005_auto_20171117_1255.py │ ├── 0004_auto_20171117_1254.py │ └── 0003_auto_20171115_1244.py ├── __init__.py ├── tests.py ├── permissions │ └── __init__.py ├── serializers │ ├── __init__.py │ ├── project_member.py │ ├── project_meeting.py │ ├── project_task.py │ └── project.py ├── signals │ ├── __init__.py │ ├── project.py │ ├── project_task.py │ └── project_member.py ├── apps.py ├── views │ ├── __init__.py │ ├── project_task_member.py │ └── project.py ├── admin │ ├── __init__.py │ ├── project_task_type.py │ ├── project.py │ ├── project_member.py │ └── project_task.py ├── models │ ├── __init__.py │ ├── project_meeting.py │ ├── project_task_type.py │ ├── project_task_history.py │ ├── project_member.py │ ├── project.py │ └── project_task.py └── urls.py ├── tcis_base ├── migrations │ └── __init__.py ├── tests.py ├── signals │ └── __init__.py ├── permissions │ └── __init__.py ├── apps.py ├── __init__.py ├── views │ ├── __init__.py │ ├── index.py │ ├── group.py │ ├── permission.py │ └── user.py ├── serializers │ ├── __init__.py │ ├── tcis_meeting.py │ ├── user.py │ ├── group.py │ ├── permission.py │ └── meeting_member.py ├── admin │ ├── __init__.py │ ├── meeting_member.py │ ├── tcis_meeting.py │ ├── position.py │ ├── department.py │ └── user.py ├── models │ ├── __init__.py │ ├── position.py │ ├── department.py │ ├── tcis_meeting.py │ ├── meeting_member.py │ └── user.py ├── paginations.py └── urls.py ├── web ├── src │ ├── pages │ │ ├── project_ci │ │ │ ├── list.vue │ │ │ ├── form.vue │ │ │ └── project_ci_home.vue │ │ ├── system │ │ │ ├── user │ │ │ │ ├── change_password.vue │ │ │ │ ├── user_form.vue │ │ │ │ └── user_home.vue │ │ │ ├── group │ │ │ │ ├── group_info.vue │ │ │ │ ├── group_list.vue │ │ │ │ ├── group_card.vue │ │ │ │ ├── group_kanban.vue │ │ │ │ ├── group_detail_home.vue │ │ │ │ └── group_form.vue │ │ │ └── permission │ │ │ │ ├── permission_list.vue │ │ │ │ └── permission_home.vue │ │ ├── project │ │ │ ├── project_task_detail_home.vue │ │ │ ├── project_form.vue │ │ │ ├── project_kanban.vue │ │ │ ├── project_task_kanban.vue │ │ │ ├── project_list.vue │ │ │ ├── project_task_gantt.vue │ │ │ ├── project_member_list.vue │ │ │ ├── project_task_card.vue │ │ │ └── project_home.vue │ │ ├── project_bug │ │ │ ├── project_bug_detail_home.vue │ │ │ ├── project_bug_kanban.vue │ │ │ ├── project_bug_card.vue │ │ │ └── project_bug_list.vue │ │ ├── project_test │ │ │ ├── project_test_detail_home.vue │ │ │ ├── project_test_kanban.vue │ │ │ ├── project_test_card.vue │ │ │ ├── project_test_list.vue │ │ │ └── project_test_card_echart.vue │ │ ├── base │ │ │ ├── footer.vue │ │ │ ├── home.vue │ │ │ ├── header.vue │ │ │ └── aside.vue │ │ └── common │ │ │ ├── middle_router_view.vue │ │ │ ├── time_axis.vue │ │ │ ├── page_404.vue │ │ │ ├── top_create.vue │ │ │ ├── tcis_select.vue │ │ │ ├── form_top.vue │ │ │ ├── pagination.vue │ │ │ └── view_switch.vue │ ├── store │ │ ├── getters.js │ │ ├── mutations-types.js │ │ ├── actions.js │ │ ├── mutations.js │ │ ├── state.js │ │ └── index.js │ ├── assets │ │ └── page_404.jpg │ ├── config │ │ └── settings.js │ ├── utils │ │ ├── filters.js │ │ ├── url_code.js │ │ └── local_store.js │ ├── App.vue │ ├── styles │ │ └── index.scss │ ├── main.js │ ├── server_address.js │ └── router.js ├── config │ ├── prod.env.js │ ├── dev.env.js │ └── index.js ├── .gitignore ├── index.html ├── build │ ├── dev-client.js │ ├── vue-loader.conf.js │ ├── build.js │ ├── webpack.dev.conf.js │ ├── check-versions.js │ ├── webpack.base.conf.js │ ├── utils.js │ └── dev-server.js ├── README.md └── package.json ├── project_bug ├── migrations │ ├── __init__.py │ ├── 0003_auto_20171115_1324.py │ ├── 0001_initial.py │ └── 0002_auto_20171115_1151.py ├── __init__.py ├── tests.py ├── permissions │ └── __init__.py ├── signals │ └── __init__.py ├── admin │ ├── __init__.py │ └── project_bug.py ├── views │ └── __init__.py ├── models │ ├── __init__.py │ └── project_bug.py ├── serializers │ ├── __init__.py │ └── project_bug.py ├── apps.py └── urls.py ├── project_test ├── migrations │ ├── __init__.py │ ├── 0003_auto_20171115_1200.py │ ├── 0004_auto_20171115_1324.py │ ├── 0001_initial.py │ └── 0002_auto_20171115_1151.py ├── __init__.py ├── tests.py ├── permissions │ └── __init__.py ├── signals │ ├── __init__.py │ └── project_test_case.py ├── apps.py ├── admin │ ├── __init__.py │ ├── project_test.py │ ├── project_test_type.py │ ├── project_test_case.py │ └── project_test_case_history.py ├── views │ ├── __init__.py │ ├── project_test_type.py │ ├── project_tase_case.py │ ├── project_test_case_history.py │ └── project_test.py ├── models │ ├── __init__.py │ ├── project_test_type.py │ ├── project_test.py │ ├── project_test_case.py │ └── project_test_case_history.py ├── serializers │ ├── __init__.py │ ├── project_test.py │ ├── project_test_case.py │ ├── project_test_type.py │ └── project_test_case_history.py └── urls.py ├── performance_appraisal ├── migrations │ └── __init__.py ├── __init__.py ├── tests.py ├── admin │ └── __init__.py ├── models │ └── __init__.py ├── views │ └── __init__.py ├── permissions │ └── __init__.py ├── serializers │ └── __init__.py ├── signals │ └── __init__.py ├── apps.py └── urls.py ├── db.sqlite3 ├── static ├── fonts │ └── element-icons.27c7209.ttf └── js │ ├── 16.16887684d55ab321b8c9.js │ ├── 17.049d493d51aa03865805.js │ ├── 18.2ea16126bf605bbc7af2.js │ ├── 15.4a0f80754bf9336425cb.js │ ├── 14.a6ab56ad507ed6cf2077.js │ ├── 13.3a548fc888b607f48c6a.js │ ├── 12.b1b737b799e9a743298f.js │ ├── 18.2ea16126bf605bbc7af2.js.map │ ├── 17.049d493d51aa03865805.js.map │ ├── 16.16887684d55ab321b8c9.js.map │ ├── manifest.56a3f94c7823145ecc26.js │ ├── 15.4a0f80754bf9336425cb.js.map │ ├── 14.a6ab56ad507ed6cf2077.js.map │ └── 13.3a548fc888b607f48c6a.js.map ├── requirements.txt ├── .gitignore ├── common └── __init__.py ├── README.md ├── templates └── index.html └── manage.py /tcis/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /project_ci/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tcis_server/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /project/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /project_ci/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tcis_base/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/src/pages/project_ci/list.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /project_bug/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /project_test/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tcis_server/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /performance_appraisal/migrations/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/src/pages/system/user/change_password.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/src/pages/project/project_task_detail_home.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/src/pages/project_bug/project_bug_detail_home.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/src/store/getters.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 3 | } -------------------------------------------------------------------------------- /web/src/pages/project_test/project_test_detail_home.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /db.sqlite3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itcloudy/tcis/HEAD/db.sqlite3 -------------------------------------------------------------------------------- /project/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | default_app_config = 'project.apps.ProjectConfig' 3 | -------------------------------------------------------------------------------- /project_bug/__init__.py: -------------------------------------------------------------------------------- 1 | default_app_config = 'project_bug.apps.ProjectBugConfig' -------------------------------------------------------------------------------- /project_test/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | default_app_config = 'project_test.apps.ProjectTestConfig' -------------------------------------------------------------------------------- /web/src/pages/base/footer.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /web/src/store/mutations-types.js: -------------------------------------------------------------------------------- 1 | export const GLOBAL_SET_USERINFO = 'GLOBAL_SET_USERINFO' // 设置用户信息 -------------------------------------------------------------------------------- /web/config/prod.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | module.exports = { 3 | NODE_ENV: '"production"' 4 | } 5 | -------------------------------------------------------------------------------- /web/src/assets/page_404.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itcloudy/tcis/HEAD/web/src/assets/page_404.jpg -------------------------------------------------------------------------------- /web/src/store/actions.js: -------------------------------------------------------------------------------- 1 | import * as types from './mutations-types' 2 | 3 | export default { 4 | 5 | } -------------------------------------------------------------------------------- /web/src/pages/common/middle_router_view.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web/src/pages/project_ci/form.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /web/src/pages/project_ci/project_ci_home.vue: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /performance_appraisal/__init__.py: -------------------------------------------------------------------------------- 1 | 2 | default_app_config = 'performance_appraisal.apps.PerformanceAppraisalConfig' 3 | 4 | -------------------------------------------------------------------------------- /static/fonts/element-icons.27c7209.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/itcloudy/tcis/HEAD/static/fonts/element-icons.27c7209.ttf -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Django==1.11.7 2 | django-suit==0.2.25 3 | djangorestframework==3.7.3 4 | channels==1.1.8 5 | django_filter==1.1.0 -------------------------------------------------------------------------------- /web/src/config/settings.js: -------------------------------------------------------------------------------- 1 | var settings = { 2 | baseUrl: "/", 3 | db_prefix: "tcis", 4 | }; 5 | module.exports = settings; 6 | -------------------------------------------------------------------------------- /web/src/pages/project/project_form.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /project/tests.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.test import TestCase 5 | 6 | # Create your tests here. 7 | -------------------------------------------------------------------------------- /project_ci/tests.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.test import TestCase 5 | 6 | # Create your tests here. 7 | -------------------------------------------------------------------------------- /tcis_base/tests.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.test import TestCase 5 | 6 | # Create your tests here. 7 | -------------------------------------------------------------------------------- /project_bug/tests.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.test import TestCase 5 | 6 | # Create your tests here. 7 | -------------------------------------------------------------------------------- /project_test/tests.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.test import TestCase 5 | 6 | # Create your tests here. 7 | -------------------------------------------------------------------------------- /tcis_server/tests.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.test import TestCase 5 | 6 | # Create your tests here. 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # sphinx build directories 2 | _build/ 3 | 4 | # dotfiles 5 | .* 6 | !.gitignore 7 | !.mailmap 8 | # compiled python files 9 | *.py[co] 10 | /node_modules/ -------------------------------------------------------------------------------- /performance_appraisal/tests.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.test import TestCase 5 | 6 | # Create your tests here. 7 | -------------------------------------------------------------------------------- /project_ci/admin/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/8 9:35 9 | """ -------------------------------------------------------------------------------- /project_ci/models/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/8 9:31 9 | """ -------------------------------------------------------------------------------- /project_ci/signals/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/9 16:32 9 | """ -------------------------------------------------------------------------------- /project_ci/views/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/8 9:35 9 | """ -------------------------------------------------------------------------------- /tcis_base/signals/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/9 16:32 9 | """ -------------------------------------------------------------------------------- /tcis_server/admin/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/10 9:49 9 | """ -------------------------------------------------------------------------------- /tcis_server/models/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/10 9:49 9 | """ -------------------------------------------------------------------------------- /tcis_server/views/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/10 9:49 9 | """ -------------------------------------------------------------------------------- /project/permissions/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/10 9:26 9 | """ -------------------------------------------------------------------------------- /project_bug/permissions/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/10 9:26 9 | """ -------------------------------------------------------------------------------- /project_bug/signals/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/9 16:32 9 | """ -------------------------------------------------------------------------------- /project_ci/permissions/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/10 9:26 9 | """ -------------------------------------------------------------------------------- /project_ci/serializers/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/9 10:07 9 | """ -------------------------------------------------------------------------------- /tcis_base/permissions/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/10 9:26 9 | """ -------------------------------------------------------------------------------- /tcis_server/permissions/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/10 9:50 9 | """ -------------------------------------------------------------------------------- /tcis_server/serializers/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/10 9:50 9 | """ -------------------------------------------------------------------------------- /tcis_server/signals/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/10 9:50 9 | """ -------------------------------------------------------------------------------- /performance_appraisal/admin/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/9 9:58 9 | """ -------------------------------------------------------------------------------- /performance_appraisal/models/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/9 9:58 9 | """ -------------------------------------------------------------------------------- /performance_appraisal/views/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/9 9:58 9 | """ -------------------------------------------------------------------------------- /project_test/permissions/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/10 9:26 9 | """ -------------------------------------------------------------------------------- /static/js/16.16887684d55ab321b8c9.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([16],{A7zi:function(l,n,u){var o=u("VU/8")(null,null,null,null,null);l.exports=o.exports}}); 2 | //# sourceMappingURL=16.16887684d55ab321b8c9.js.map -------------------------------------------------------------------------------- /static/js/17.049d493d51aa03865805.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([17],{wRKD:function(l,n,u){var o=u("VU/8")(null,null,null,null,null);l.exports=o.exports}}); 2 | //# sourceMappingURL=17.049d493d51aa03865805.js.map -------------------------------------------------------------------------------- /static/js/18.2ea16126bf605bbc7af2.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([18],{hFY9:function(l,n,u){var o=u("VU/8")(null,null,null,null,null);l.exports=o.exports}}); 2 | //# sourceMappingURL=18.2ea16126bf605bbc7af2.js.map -------------------------------------------------------------------------------- /performance_appraisal/permissions/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/10 9:26 9 | """ -------------------------------------------------------------------------------- /performance_appraisal/serializers/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/9 10:07 9 | """ -------------------------------------------------------------------------------- /performance_appraisal/signals/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/9 16:32 9 | """ -------------------------------------------------------------------------------- /web/config/dev.env.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const merge = require('webpack-merge') 3 | const prodEnv = require('./prod.env') 4 | 5 | module.exports = merge(prodEnv, { 6 | NODE_ENV: '"development"' 7 | }) 8 | -------------------------------------------------------------------------------- /project_ci/apps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.apps import AppConfig 5 | 6 | 7 | class ProjectCiConfig(AppConfig): 8 | name = 'project_ci' 9 | -------------------------------------------------------------------------------- /tcis_server/apps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.apps import AppConfig 5 | 6 | 7 | class TcisServerConfig(AppConfig): 8 | name = 'tcis_server' 9 | -------------------------------------------------------------------------------- /common/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/11 11:00 9 | """ 10 | from .parent_tree import * -------------------------------------------------------------------------------- /project_bug/admin/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/8 9:35 9 | """ 10 | from .project_bug import * -------------------------------------------------------------------------------- /project_bug/views/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/8 9:35 9 | """ 10 | from .project_bug import * 11 | -------------------------------------------------------------------------------- /project_bug/models/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/8 9:31 9 | """ 10 | 11 | from .project_bug import * -------------------------------------------------------------------------------- /project_bug/serializers/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/9 10:07 9 | """ 10 | from .project_bug import * -------------------------------------------------------------------------------- /web/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Editor directories and files 9 | .idea 10 | .vscode 11 | *.suo 12 | *.ntvs* 13 | *.njsproj 14 | *.sln 15 | -------------------------------------------------------------------------------- /tcis_base/apps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.apps import AppConfig 5 | 6 | 7 | class TcisBaseConfig(AppConfig): 8 | name = 'tcis_base' 9 | verbose_name = u'基本配置' 10 | -------------------------------------------------------------------------------- /project_test/signals/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/9 16:32 9 | """ 10 | from .project_test_case import * 11 | 12 | -------------------------------------------------------------------------------- /project_bug/apps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.apps import AppConfig 5 | 6 | 7 | class ProjectBugConfig(AppConfig): 8 | name = 'project_bug' 9 | verbose_name = u'项目Bug' 10 | -------------------------------------------------------------------------------- /web/src/pages/common/time_axis.vue: -------------------------------------------------------------------------------- 1 | 6 | 11 | 14 | 15 | -------------------------------------------------------------------------------- /tcis_base/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/8 9:35 9 | """ 10 | 11 | default_app_config = 'tcis_base.apps.TcisBaseConfig' 12 | 13 | -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | tcis_web 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /web/src/store/mutations.js: -------------------------------------------------------------------------------- 1 | import * as types from './mutations-types' 2 | 3 | export default { 4 | [types.GLOBAL_SET_USERINFO](state, userinfo) { 5 | state.userinfo = userinfo; 6 | state.isBackgroundUser = userinfo.isBackground; 7 | }, 8 | 9 | } -------------------------------------------------------------------------------- /project_ci/urls.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:urls.py 8 | @date:2017/11/8 10:07 9 | """ 10 | 11 | from django.conf.urls import url 12 | from . import views 13 | 14 | urlpatterns = [] -------------------------------------------------------------------------------- /performance_appraisal/apps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.apps import AppConfig 5 | 6 | 7 | class PerformanceAppraisalConfig(AppConfig): 8 | name = 'performance_appraisal' 9 | verbose_name = u'绩效考核' 10 | -------------------------------------------------------------------------------- /performance_appraisal/urls.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:urls.py 8 | @date:2017/11/8 10:06 9 | """ 10 | from django.conf.urls import url 11 | from . import views 12 | 13 | urlpatterns = [ 14 | 15 | ] -------------------------------------------------------------------------------- /project/serializers/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/9 10:07 9 | """ 10 | 11 | from .project import * 12 | from .project_member import * 13 | from .project_task import * 14 | -------------------------------------------------------------------------------- /project/signals/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/9 16:32 9 | """ 10 | from .project import * 11 | from .project_member import * 12 | from .project_task import * 13 | 14 | 15 | -------------------------------------------------------------------------------- /web/src/utils/filters.js: -------------------------------------------------------------------------------- 1 | export default function stringTimeFormat(timeString) { 2 | let date = new Date(timeString); 3 | let time = date.toLocaleString(); 4 | time = time.replace(/\//g, "-"); 5 | time = time.replace("上午", ""); 6 | time = time.replace("下午", ""); 7 | return time; 8 | } -------------------------------------------------------------------------------- /tcis_base/views/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/8 9:35 9 | """ 10 | 11 | from .index import * 12 | from .user import * 13 | from .group import * 14 | from .permission import * 15 | -------------------------------------------------------------------------------- /project/apps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.apps import AppConfig 5 | 6 | 7 | class ProjectConfig(AppConfig): 8 | name = 'project' 9 | verbose_name = u'项目' 10 | 11 | def ready(self): 12 | import project.signals 13 | 14 | -------------------------------------------------------------------------------- /project/views/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/8 9:35 9 | """ 10 | 11 | 12 | from .project import * 13 | from .project_task import * 14 | from .project_task_member import * 15 | 16 | -------------------------------------------------------------------------------- /web/src/pages/common/page_404.vue: -------------------------------------------------------------------------------- 1 | 6 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /project/admin/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/8 9:35 9 | """ 10 | from .project import * 11 | from .project_member import * 12 | from .project_task import * 13 | from .project_task_type import * 14 | -------------------------------------------------------------------------------- /web/build/dev-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | 'use strict' 3 | require('eventsource-polyfill') 4 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 5 | 6 | hotClient.subscribe(function (event) { 7 | if (event.action === 'reload') { 8 | window.location.reload() 9 | } 10 | }) 11 | -------------------------------------------------------------------------------- /project_test/apps.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import unicode_literals 3 | 4 | from django.apps import AppConfig 5 | 6 | 7 | class ProjectTestConfig(AppConfig): 8 | name = 'project_test' 9 | verbose_name = u'项目测试' 10 | 11 | def ready(self): 12 | import project_test.signals 13 | 14 | -------------------------------------------------------------------------------- /tcis_base/serializers/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/9 10:07 9 | """ 10 | from .user import * 11 | from .group import * 12 | from .tcis_meeting import TcisMeetingSerializer 13 | from .permission import * -------------------------------------------------------------------------------- /web/src/pages/system/user/user_form.vue: -------------------------------------------------------------------------------- 1 | 6 | 16 | 17 | -------------------------------------------------------------------------------- /static/js/15.4a0f80754bf9336425cb.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([15],{OEdk:function(e,n){e.exports={render:function(){var e=this,n=e.$createElement;return(e._self._c||n)("router-view")},staticRenderFns:[]}},cBoM:function(e,n,r){var t=r("VU/8")(null,r("OEdk"),null,null,null);e.exports=t.exports}}); 2 | //# sourceMappingURL=15.4a0f80754bf9336425cb.js.map -------------------------------------------------------------------------------- /project_test/admin/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/8 9:35 9 | """ 10 | from .project_test_case_history import * 11 | from .project_test import * 12 | from .project_test_type import * 13 | from .project_test_case import * -------------------------------------------------------------------------------- /project_test/views/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/8 9:35 9 | """ 10 | from .project_test import * 11 | from .project_tase_case import * 12 | from .project_test_case_history import * 13 | from .project_test_type import * 14 | -------------------------------------------------------------------------------- /static/js/14.a6ab56ad507ed6cf2077.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([14],{C2W4:function(n,e){n.exports={render:function(){var n=this,e=n.$createElement;return(n._self._c||e)("p",[n._v(" project ci info")])},staticRenderFns:[]}},obhH:function(n,e,t){var r=t("VU/8")(null,t("C2W4"),null,null,null);n.exports=r.exports}}); 2 | //# sourceMappingURL=14.a6ab56ad507ed6cf2077.js.map -------------------------------------------------------------------------------- /tcis_base/admin/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/8 9:35 9 | """ 10 | from .department import * 11 | from .user import * 12 | from .position import * 13 | from .tcis_meeting import * 14 | from .meeting_member import * 15 | 16 | -------------------------------------------------------------------------------- /static/js/13.3a548fc888b607f48c6a.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([13],{"0Qf1":function(n,e,t){var r=t("VU/8")(null,t("SIth"),null,null,null);n.exports=r.exports},SIth:function(n,e){n.exports={render:function(){var n=this,e=n.$createElement;return(n._self._c||e)("p",[n._v("project ci kanban ")])},staticRenderFns:[]}}}); 2 | //# sourceMappingURL=13.3a548fc888b607f48c6a.js.map -------------------------------------------------------------------------------- /tcis_base/models/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/8 9:31 9 | """ 10 | 11 | from .user import * 12 | from .department import * 13 | from .position import * 14 | from .tcis_meeting import * 15 | from .meeting_member import * 16 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 项目说明 2 | 是一个用于管理软件项目开发的app,包括项目管理,项目任务管理,项目测试管理,项目bug管理 3 | 4 | ## 说明 5 | * 后台 框架为djangorestframework 6 | * 前端 基于vue2.0 7 | 8 | * tcis_base:基础模块,用户改进,部门,职位,会议 9 | * tcis_server:服务器管理 10 | * performance_appraisal:绩效考核 11 | * project:项目管理:项目,任务,项目会议 12 | * project_ci:持续集成 13 | * project_test:测试管理:用例 14 | * projct_bug:项目bug管理 15 | -------------------------------------------------------------------------------- /project_test/models/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/8 9:31 9 | """ 10 | from .project_test_case import * 11 | from .project_test import * 12 | from .project_test_type import * 13 | from .project_test_case_history import * 14 | 15 | -------------------------------------------------------------------------------- /project_test/serializers/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/9 10:07 9 | """ 10 | from .project_test import * 11 | from .project_test_case_history import * 12 | from .project_test_case import * 13 | from .project_test_type import * 14 | -------------------------------------------------------------------------------- /web/src/App.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 15 | 16 | 19 | -------------------------------------------------------------------------------- /web/src/utils/url_code.js: -------------------------------------------------------------------------------- 1 | export default function urlCode(data) { 2 | let urlQueryList = []; 3 | if (typeof(data) == 'undefined' || data == null || typeof(data) != 'object') { 4 | return ''; 5 | } 6 | for (let k in data) { 7 | urlQueryList.push("" + k + "=" + encodeURI(data[k])) 8 | } 9 | return urlQueryList.join("&"); 10 | } -------------------------------------------------------------------------------- /tcis_base/views/index.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:index.py 8 | @date:2017/11/8 13:55 9 | """ 10 | from django.shortcuts import render 11 | 12 | 13 | def index(request): 14 | """ 15 | 首页 16 | :param request: 17 | :return: 18 | """ 19 | return render(request, 'index.html') 20 | -------------------------------------------------------------------------------- /project_bug/urls.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:urls.py 8 | @date:2017/11/8 10:06 9 | """ 10 | from rest_framework import routers 11 | from .views import * 12 | 13 | router = routers.DefaultRouter() 14 | 15 | router.register(r'project_bug', ProjectBugViewSet, 'project_bug') 16 | 17 | urlpatterns = router.urls 18 | -------------------------------------------------------------------------------- /tcis_base/paginations.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:paginations.py 8 | @date:2017/11/9 11:15 9 | """ 10 | from rest_framework import pagination 11 | 12 | 13 | class DefaultPagination(pagination.PageNumberPagination): 14 | page_size = 20 15 | max_page_size = 10000 16 | page_size_query_param = 'page_size' 17 | -------------------------------------------------------------------------------- /web/src/store/state.js: -------------------------------------------------------------------------------- 1 | import localStore from 'utils/local_store'; 2 | const state = { 3 | //登录成功后的用户信息 4 | userinfo: JSON.parse(localStore.get('userinfo')) || {}, 5 | //后台获得的菜单(后台菜单) 6 | backgroundMenus: JSON.parse(localStore.get('backgroundMenus')) || {}, 7 | // 加载路由完成 8 | loadRoutersDone: false, 9 | //可以访问后台 10 | isBackgroundUser: false, 11 | }; 12 | export default state -------------------------------------------------------------------------------- /project/models/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:__init__.py.py 8 | @date:2017/11/8 9:31 9 | """ 10 | from .project import * 11 | from .project_member import * 12 | from .project_task import * 13 | from .project_meeting import * 14 | from .project_task_type import * 15 | from .project_task_history import * 16 | 17 | 18 | -------------------------------------------------------------------------------- /project_test/admin/project_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_test.py 8 | @date:2017/11/15 11:52 9 | """ 10 | from django.contrib import admin 11 | from ..models import ProjectTest 12 | 13 | 14 | @admin.register(ProjectTest) 15 | class ProjectTestAdmin(admin.ModelAdmin): 16 | list_display = ['project', 'name', 'type'] 17 | -------------------------------------------------------------------------------- /project_test/admin/project_test_type.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_test_type.py 8 | @date:2017/11/15 11:53 9 | """ 10 | from django.contrib import admin 11 | from ..models import ProjectTestType 12 | 13 | 14 | @admin.register(ProjectTestType) 15 | class ProjectTestTypeAdmin(admin.ModelAdmin): 16 | list_display = ['name'] 17 | 18 | -------------------------------------------------------------------------------- /tcis_base/serializers/tcis_meeting.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:tcis_meeting.py 8 | @date:2017/11/15 11:14 9 | """ 10 | from rest_framework import serializers 11 | from ..models import TcisMeeting 12 | 13 | 14 | class TcisMeetingSerializer(serializers.ModelSerializer): 15 | class Meta: 16 | model = TcisMeeting 17 | depth = 2 18 | 19 | -------------------------------------------------------------------------------- /tcis_base/serializers/user.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:user.py 8 | @date:2017/11/10 9:10 9 | """ 10 | from rest_framework import serializers 11 | from ..models import User 12 | 13 | 14 | class UserSerializer(serializers.ModelSerializer): 15 | class Meta: 16 | model = User 17 | depth = 2 18 | exclude = ('password',) 19 | 20 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | tcis_web
-------------------------------------------------------------------------------- /project/admin/project_task_type.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_task_type.py 8 | @date:2017/11/15 12:42 9 | """ 10 | from django.contrib import admin 11 | from ..models import ProjectTaskType 12 | 13 | 14 | @admin.register(ProjectTaskType) 15 | class ProjectTaskTypeAdmin(admin.ModelAdmin): 16 | """ 17 | 项目管理后台 18 | """ 19 | list_display = ["name"] 20 | -------------------------------------------------------------------------------- /project_test/admin/project_test_case.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_test_case.py 8 | @date:2017/11/15 11:53 9 | """ 10 | from django.contrib import admin 11 | from ..models import ProjectTestCase 12 | 13 | 14 | @admin.register(ProjectTestCase) 15 | class ProjectTestCaseAdmin(admin.ModelAdmin): 16 | list_display = ['project', 'task', 'test', "name", "type"] 17 | 18 | -------------------------------------------------------------------------------- /tcis_base/serializers/group.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:group.py 8 | @date:2017/11/13 17:15 9 | """ 10 | from django.contrib.auth.models import Group 11 | from rest_framework import serializers 12 | 13 | 14 | class GroupSerializer(serializers.ModelSerializer): 15 | 16 | class Meta: 17 | model = Group 18 | depth = 2 19 | fields = "__all__" 20 | 21 | -------------------------------------------------------------------------------- /tcis/wsgi.py: -------------------------------------------------------------------------------- 1 | """ 2 | WSGI config for tcis project. 3 | 4 | It exposes the WSGI callable as a module-level variable named ``application``. 5 | 6 | For more information on this file, see 7 | https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/ 8 | """ 9 | 10 | import os 11 | 12 | from django.core.wsgi import get_wsgi_application 13 | 14 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tcis.settings") 15 | 16 | application = get_wsgi_application() 17 | -------------------------------------------------------------------------------- /project_test/admin/project_test_case_history.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_test_case_history.py 8 | @date:2017/11/15 11:53 9 | """ 10 | from django.contrib import admin 11 | from ..models import ProjectTestCaseHistory 12 | 13 | 14 | @admin.register(ProjectTestCaseHistory) 15 | class ProjectTestCaseHistoryAdmin(admin.ModelAdmin): 16 | list_display = ['case', 'user'] 17 | 18 | -------------------------------------------------------------------------------- /project_test/serializers/project_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_test.py 8 | @date:2017/11/15 13:19 9 | """ 10 | 11 | from rest_framework import serializers 12 | from ..models import ProjectTest 13 | 14 | 15 | class ProjectTestSerializer(serializers.ModelSerializer): 16 | class Meta: 17 | model = ProjectTest 18 | depth = 1 19 | fields = "__all__" 20 | -------------------------------------------------------------------------------- /project_test/serializers/project_test_case.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_test_case.py 8 | @date:2017/11/15 15:10 9 | """ 10 | from rest_framework import serializers 11 | from ..models import ProjectTestCase 12 | 13 | 14 | class ProjectTestCaseSerializer(serializers.ModelSerializer): 15 | class Meta: 16 | model = ProjectTestCase 17 | depth = 1 18 | fields = "__all__" -------------------------------------------------------------------------------- /tcis_base/serializers/permission.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:permission.py 8 | @date:2017/11/15 17:54 9 | """ 10 | from django.contrib.auth.models import Permission 11 | from rest_framework import serializers 12 | 13 | 14 | class PermissionSerializer(serializers.ModelSerializer): 15 | 16 | class Meta: 17 | model = Permission 18 | depth = 2 19 | fields = "__all__" 20 | -------------------------------------------------------------------------------- /project_test/serializers/project_test_type.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_test_type.py 8 | @date:2017/11/15 15:10 9 | """ 10 | from rest_framework import serializers 11 | from ..models import ProjectTestType 12 | 13 | 14 | class ProjectTestTypeSerializer(serializers.ModelSerializer): 15 | class Meta: 16 | model = ProjectTestType 17 | depth = 1 18 | fields = "__all__" 19 | -------------------------------------------------------------------------------- /tcis_base/admin/meeting_member.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:meeting_member.py 8 | @date:2017/11/15 11:06 9 | """ 10 | from django.contrib import admin 11 | 12 | from ..models import MeetingMember 13 | 14 | 15 | @admin.register(MeetingMember) 16 | class MeetingMemberAdmin(admin.ModelAdmin): 17 | """会议管理""" 18 | list_display = ['meeting', "user", "state"] 19 | list_filter = ["user", "state"] 20 | -------------------------------------------------------------------------------- /tcis_base/views/group.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:group.py 8 | @date:2017/11/13 17:16 9 | """ 10 | from rest_framework import viewsets 11 | from django.contrib.auth.models import Group 12 | from ..serializers import GroupSerializer 13 | 14 | 15 | class GroupViewSet(viewsets.ModelViewSet): 16 | """ 17 | 用户 18 | """ 19 | queryset = Group.objects.all() 20 | serializer_class = GroupSerializer 21 | 22 | -------------------------------------------------------------------------------- /tcis_server/models/server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:server.py 8 | @date:2017/11/10 10:07 9 | """ 10 | from django.db import models 11 | 12 | 13 | class Server(models.Model): 14 | """ 15 | 服务器管理 16 | """ 17 | name = models.CharField(max_length=20, verbose_name=u"服务器名称") 18 | ip = models.IPAddressField(verbose_name=u"服务器IP地址") 19 | system = models.CharField(max_length=20, verbose_name=u"服务器系统") -------------------------------------------------------------------------------- /project/admin/project.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project.py 8 | @date:2017/11/9 9:04 9 | """ 10 | 11 | from django.contrib import admin 12 | from ..models import Project 13 | 14 | 15 | @admin.register(Project) 16 | class ProjectAdmin(admin.ModelAdmin): 17 | """ 18 | 项目管理后台 19 | """ 20 | list_display = ["name", "manager", "active", "parent", "start_date", "end_date", "parent_left", "parent_right"] 21 | 22 | -------------------------------------------------------------------------------- /project_test/serializers/project_test_case_history.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_test_case_history.py 8 | @date:2017/11/15 15:10 9 | """ 10 | from rest_framework import serializers 11 | from ..models import ProjectTestCaseHistory 12 | 13 | 14 | class ProjectTestCaseHistorySerializer(serializers.ModelSerializer): 15 | class Meta: 16 | model = ProjectTestCaseHistory 17 | depth = 1 18 | fields = "__all__" 19 | -------------------------------------------------------------------------------- /tcis_base/admin/tcis_meeting.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:tcis_meeting.py 8 | @date:2017/11/15 10:51 9 | """ 10 | from django.contrib import admin 11 | 12 | from ..models import TcisMeeting 13 | 14 | 15 | @admin.register(TcisMeeting) 16 | class TcisMeetingAdmin(admin.ModelAdmin): 17 | """会议管理""" 18 | list_display = ['title', "moderator", "recorder", 'start_time', 'end_time'] 19 | list_filter = ["moderator", "recorder"] 20 | 21 | -------------------------------------------------------------------------------- /project/migrations/0005_auto_20171117_1255.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.7 on 2017-11-17 04:55 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('project', '0004_auto_20171117_1254'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterModelTable( 16 | name='projectmeeting', 17 | table='project_meeting', 18 | ), 19 | ] 20 | -------------------------------------------------------------------------------- /web/build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const config = require('../config') 4 | const isProduction = process.env.NODE_ENV === 'production' 5 | 6 | module.exports = { 7 | loaders: utils.cssLoaders({ 8 | sourceMap: isProduction 9 | ? config.build.productionSourceMap 10 | : config.dev.cssSourceMap, 11 | extract: isProduction 12 | }), 13 | transformToRequire: { 14 | video: 'src', 15 | source: 'src', 16 | img: 'src', 17 | image: 'xlink:href' 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /web/README.md: -------------------------------------------------------------------------------- 1 | # tcis_web 2 | 3 | > tcis 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:8080 12 | npm run dev 13 | 14 | # build for production with minification 15 | npm run build 16 | 17 | # build for production and view the bundle analyzer report 18 | npm run build --report 19 | ``` 20 | 21 | For a detailed explanation on how things work, check out the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 22 | -------------------------------------------------------------------------------- /project/urls.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:urls.py 8 | @date:2017/11/8 10:06 9 | """ 10 | from django.conf.urls import url 11 | from rest_framework import routers 12 | from .views import * 13 | 14 | router = routers.DefaultRouter() 15 | 16 | router.register(r'project', ProjectViewSet, 'project') 17 | router.register(r'project_task', ProjectTaskViewSet, 'project_task') 18 | router.register(r'project_member', ProjectMemberViewSet, 'project_member') 19 | 20 | urlpatterns = router.urls 21 | -------------------------------------------------------------------------------- /web/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | // 根级state、actions、getters、mutations 5 | import state from './state'; 6 | import actions from './actions'; 7 | import getters from './getters'; 8 | import mutations from './mutations'; 9 | 10 | 11 | Vue.use(Vuex) 12 | const debug = process.env.NODE_ENV !== 'production' 13 | 14 | export default new Vuex.Store({ 15 | state, 16 | actions, 17 | getters, 18 | mutations, 19 | modules: { 20 | // adminPartner, //合作伙伴 21 | 22 | }, 23 | strict: debug, 24 | }) 25 | -------------------------------------------------------------------------------- /project/signals/project.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project.py 8 | @date:2017/11/9 16:45 9 | """ 10 | from django.db.models.signals import pre_save 11 | from django.dispatch import receiver 12 | from ..models import Project 13 | 14 | 15 | @receiver(pre_save, sender=Project) 16 | def save_project(sender, instance, *args, **kwargs): 17 | """ 18 | 19 | :param sender: 20 | :param instance: 21 | :param args: 22 | :param kwargs: 23 | :return: 24 | """ 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /project/admin/project_member.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_member.py 8 | @date:2017/11/9 16:23 9 | """ 10 | from django.contrib import admin 11 | from ..models import ProjectMember 12 | 13 | 14 | @admin.register(ProjectMember) 15 | class ProjectMemberAdmin(admin.ModelAdmin): 16 | """ 17 | 项目管理后台 18 | """ 19 | list_display = ["project", "member", "active", "position"] 20 | 21 | fieldsets = [ 22 | (None, { 23 | 'fields': ['project', 'member']}) 24 | ] 25 | -------------------------------------------------------------------------------- /project/signals/project_task.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_task.py 8 | @date:2017/11/9 16:46 9 | """ 10 | 11 | from django.db.models.signals import pre_save 12 | from django.dispatch import receiver 13 | from ..models import ProjectTask 14 | 15 | 16 | @receiver(pre_save, sender=ProjectTask) 17 | def save_project_task(sender, instance, *args, **kwargs): 18 | """ 19 | 20 | :param sender: 21 | :param instance: 22 | :param args: 23 | :param kwargs: 24 | :return: 25 | """ 26 | -------------------------------------------------------------------------------- /project/serializers/project_member.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_member.py 8 | @date:2017/11/10 11:49 9 | """ 10 | from rest_framework import serializers 11 | from ..models import ProjectMember 12 | 13 | 14 | class ProjectMemberSerializer(serializers.ModelSerializer): 15 | parent_left = serializers.IntegerField(read_only=True) 16 | parent_right = serializers.IntegerField(read_only=True) 17 | 18 | class Meta: 19 | model = ProjectMember 20 | depth = 1 21 | fields = "__all__" 22 | -------------------------------------------------------------------------------- /project_bug/admin/project_bug.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_bug.py 8 | @date:2017/11/9 16:23 9 | """ 10 | from django.contrib import admin 11 | from ..models import ProjectBug 12 | 13 | 14 | @admin.register(ProjectBug) 15 | class ProjectBugAdmin(admin.ModelAdmin): 16 | """ 17 | 项目管理后台 18 | """ 19 | search_fields = ["project", "name", "handler", "state"] 20 | list_display = ["project", "name", "handler", "state"] 21 | list_filter = ['project', "handler", "state", 'tester', 'checker'] 22 | 23 | -------------------------------------------------------------------------------- /tcis_base/urls.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:urls.py 8 | @date:2017/11/8 10:07 9 | """ 10 | 11 | from django.conf.urls import url 12 | from .views import * 13 | from rest_framework import routers 14 | 15 | 16 | urlpatterns = [ 17 | url(r'^$', index, name="index"), 18 | ] 19 | router = routers.DefaultRouter() 20 | 21 | router.register(r'user', UserViewSet, 'user') 22 | router.register(r'group', GroupViewSet, 'group') 23 | router.register(r'permission', PermissionViewSet, 'permission') 24 | urlpatterns += router.urls 25 | -------------------------------------------------------------------------------- /tcis_base/serializers/meeting_member.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:meeting_member.py 8 | @date:2017/11/15 11:16 9 | """ 10 | from rest_framework import serializers 11 | from ..models import MeetingMember 12 | from .user import UserSerializer 13 | from .tcis_meeting import TcisMeetingSerializer 14 | 15 | 16 | class MeetingMemberSerializer(serializers.ModelSerializer): 17 | meeting = TcisMeetingSerializer() 18 | user = UserSerializer() 19 | 20 | class Meta: 21 | model = MeetingMember 22 | depth = 2 23 | -------------------------------------------------------------------------------- /project/models/project_meeting.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_meeting.py 8 | @date:2017/11/15 10:48 9 | """ 10 | from django.db import models 11 | 12 | 13 | class ProjectMeeting(models.Model): 14 | """ 15 | 项目会议 16 | """ 17 | meeting = models.ForeignKey('tcis_base.TcisMeeting', verbose_name=u"会议") 18 | project = models.ForeignKey("Project", verbose_name=u"项目") 19 | 20 | class Meta: 21 | db_table = "project_meeting" 22 | verbose_name = u'项目会议' 23 | verbose_name_plural = u"项目会议管理" 24 | -------------------------------------------------------------------------------- /tcis_base/admin/position.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:position.py 8 | @date:2017/11/9 16:47 9 | """ 10 | from django.contrib import admin 11 | 12 | from ..models import Position 13 | 14 | 15 | @admin.register(Position) 16 | class PositionAdmin(admin.ModelAdmin): 17 | """ 18 | 用户后台信息管理 19 | """ 20 | search_fields = ['name'] 21 | list_display = ['name', "description"] 22 | list_filter = ['name'] 23 | 24 | fieldsets = [ 25 | (None,{ 26 | 'fields': ['name', 'description'], 27 | }), 28 | 29 | ] 30 | 31 | -------------------------------------------------------------------------------- /project/serializers/project_meeting.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_meeting.py 8 | @date:2017/11/15 11:12 9 | """ 10 | from rest_framework import serializers 11 | from ..models import ProjectMeeting 12 | from .project import ProjectSerializer 13 | from tcis_base.serializers import TcisMeetingSerializer 14 | 15 | 16 | class ProjectMeetingSerializer(serializers.ModelSerializer): 17 | meeting = TcisMeetingSerializer() 18 | project = ProjectSerializer() 19 | 20 | class Meta: 21 | model = ProjectMeeting 22 | depth = 2 23 | fields = "__all__" 24 | -------------------------------------------------------------------------------- /project_test/urls.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:urls.py 8 | @date:2017/11/8 10:07 9 | """ 10 | from rest_framework import routers 11 | from .views import * 12 | 13 | router = routers.DefaultRouter() 14 | 15 | router.register(r'project_test', ProjectTestViewSet, 'project_test') 16 | router.register(r'project_test_case', ProjectTestCaseViewSet, 'project_test_case') 17 | router.register(r'project_test_case_history', ProjectTestCaseHistoryViewSet, 'project_test_case_history') 18 | router.register(r'project_test_type', ProjectTestTypeViewSet, 'project_test_type') 19 | 20 | urlpatterns = router.urls 21 | -------------------------------------------------------------------------------- /project/serializers/project_task.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_task.py 8 | @date:2017/11/10 11:49 9 | """ 10 | 11 | from rest_framework import serializers 12 | from ..models import ProjectTask 13 | from tcis_base.serializers import UserSerializer 14 | 15 | 16 | class ProjectTaskSerializer(serializers.ModelSerializer): 17 | parent_left = serializers.IntegerField(read_only=True) 18 | parent_right = serializers.IntegerField(read_only=True) 19 | handler = UserSerializer() 20 | 21 | class Meta: 22 | model = ProjectTask 23 | depth = 1 24 | fields = "__all__" 25 | -------------------------------------------------------------------------------- /project_test/models/project_test_type.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:test_type.py 8 | @date:2017/11/15 11:24 9 | """ 10 | from django.db import models 11 | 12 | 13 | class ProjectTestType(models.Model): 14 | """ 15 | 测试类型 16 | """ 17 | name = models.CharField(verbose_name=u"测试类型", max_length=20, unique=True) 18 | 19 | def __unicode__(self): 20 | return self.name 21 | 22 | def __str__(self): 23 | return self.name 24 | 25 | class Meta: 26 | db_table = "project_test_type" 27 | verbose_name = u'测试类型' 28 | verbose_name_plural = u"测试类型" 29 | -------------------------------------------------------------------------------- /project/models/project_task_type.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_task_type.py 8 | @date:2017/11/15 11:30 9 | """ 10 | from django.db import models 11 | 12 | 13 | class ProjectTaskType(models.Model): 14 | """ 15 | 任务类型 16 | """ 17 | name = models.CharField(verbose_name=u"任务类型", max_length=20, unique=True) 18 | 19 | def __unicode__(self): 20 | return self.name 21 | 22 | def __str__(self): 23 | return self.name 24 | 25 | class Meta: 26 | db_table = "project_task_type" 27 | verbose_name = u'任务类型' 28 | verbose_name_plural = u"任务类型管理" 29 | -------------------------------------------------------------------------------- /web/src/pages/project/project_kanban.vue: -------------------------------------------------------------------------------- 1 | 8 | 24 | -------------------------------------------------------------------------------- /project_test/signals/project_test_case.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:test_case.py 8 | @date:2017/11/15 13:06 9 | """ 10 | from django.db.models.signals import pre_save 11 | from django.dispatch import receiver 12 | from ..models import ProjectTestCase 13 | 14 | 15 | @receiver(pre_save, sender=ProjectTestCase) 16 | def save_test_case(sender, instance, *args, **kwargs): 17 | """ 18 | 19 | :param sender: 20 | :param instance: 21 | :param args: 22 | :param kwargs: 23 | :return: 24 | """ 25 | if instance and instance.test and instance.test.type: 26 | instance.type = instance.test.type 27 | -------------------------------------------------------------------------------- /project/migrations/0004_auto_20171117_1254.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.7 on 2017-11-17 04:54 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('project', '0003_auto_20171115_1244'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterModelOptions( 16 | name='projectmeeting', 17 | options={'verbose_name': '项目会议', 'verbose_name_plural': '项目会议管理'}, 18 | ), 19 | migrations.AlterModelTable( 20 | name='projectmeeting', 21 | table='project_member', 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /tcis_base/models/position.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:position.py 8 | @date:2017/11/8 11:07 9 | """ 10 | 11 | from django.db import models 12 | 13 | 14 | class Position(models.Model): 15 | """ 16 | 职位 17 | """ 18 | name = models.CharField(max_length=20, verbose_name=u"职位", unique=True, null=False) 19 | description = models.TextField(verbose_name=u"职位描述", null=True, blank=True) 20 | 21 | def __unicode__(self): 22 | return self.name 23 | 24 | def __str__(self): 25 | return self.name 26 | 27 | class Meta: 28 | verbose_name = u'职位' 29 | verbose_name_plural = u'职位管理' -------------------------------------------------------------------------------- /project/migrations/0003_auto_20171115_1244.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.7 on 2017-11-15 04:44 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('project', '0002_auto_20171115_1151'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterModelOptions( 16 | name='projecttasktype', 17 | options={'verbose_name': '任务类型', 'verbose_name_plural': '任务类型管理'}, 18 | ), 19 | migrations.AlterModelTable( 20 | name='projecttasktype', 21 | table='project_task_type', 22 | ), 23 | ] 24 | -------------------------------------------------------------------------------- /project/signals/project_member.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project.py 8 | @date:2017/11/9 16:34 9 | """ 10 | from django.db.models.signals import pre_save 11 | from django.dispatch import receiver 12 | from ..models import ProjectMember 13 | 14 | 15 | @receiver(pre_save, sender=ProjectMember) 16 | def save_project_member(sender, instance, *args, **kwargs): 17 | """ 18 | 19 | :param sender: 20 | :param instance: 21 | :param args: 22 | :param kwargs: 23 | :return: 24 | """ 25 | if instance and instance.member and instance.member.position: 26 | instance.position = instance.member.position 27 | 28 | 29 | -------------------------------------------------------------------------------- /web/src/pages/base/home.vue: -------------------------------------------------------------------------------- 1 | 12 | 28 | -------------------------------------------------------------------------------- /web/src/pages/common/top_create.vue: -------------------------------------------------------------------------------- 1 | 6 | 24 | 30 | -------------------------------------------------------------------------------- /tcis_base/admin/department.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:department.py 8 | @date:2017/11/9 16:49 9 | """ 10 | from django.contrib import admin 11 | 12 | from ..models import Department 13 | 14 | 15 | @admin.register(Department) 16 | class DepartmentAdmin(admin.ModelAdmin): 17 | """ 18 | 用户后台信息管理 19 | """ 20 | search_fields = ['name', "parent", "charge"] 21 | list_display = ['name', "parent", "charge"] 22 | list_filter = ['name'] 23 | 24 | fieldsets = [ 25 | (u"基本信息",{ 26 | 'fields': ['name', 'parent', "charge"], 27 | }), 28 | (u"其他信息", { 29 | 'fields': ['description'], 30 | }), 31 | 32 | ] 33 | -------------------------------------------------------------------------------- /project_test/views/project_test_type.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_test_type.py 8 | @date:2017/11/15 15:08 9 | """ 10 | from rest_framework import status, permissions 11 | from rest_framework.decorators import list_route 12 | from rest_framework import viewsets 13 | from django.db.models import Count 14 | from project_test.models import ProjectTestType 15 | from rest_framework.response import Response 16 | from tcis_base.models import User 17 | from ..serializers import * 18 | 19 | 20 | class ProjectTestTypeViewSet(viewsets.ModelViewSet): 21 | """ 22 | 项目管理 23 | """ 24 | queryset = ProjectTestType.objects.all() 25 | serializer_class = ProjectTestTypeSerializer -------------------------------------------------------------------------------- /project_test/views/project_tase_case.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_tase_case.py 8 | @date:2017/11/15 15:08 9 | """ 10 | from rest_framework import status, permissions 11 | from rest_framework.decorators import list_route 12 | from rest_framework import viewsets 13 | from django.db.models import Count 14 | from project_test.models import ProjectTestCase 15 | from rest_framework.response import Response 16 | from tcis_base.models import User 17 | from ..serializers import * 18 | 19 | 20 | class ProjectTestCaseViewSet(viewsets.ModelViewSet): 21 | """ 22 | 项目管理 23 | """ 24 | queryset = ProjectTestCase.objects.all() 25 | serializer_class = ProjectTestCaseSerializer 26 | 27 | -------------------------------------------------------------------------------- /project_bug/serializers/project_bug.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_task.py 8 | @date:2017/11/10 11:49 9 | """ 10 | 11 | from rest_framework import serializers 12 | from ..models import ProjectBug 13 | from tcis_base.serializers import UserSerializer 14 | from project.serializers import ProjectSerializer, ProjectTaskSerializer 15 | 16 | 17 | class ProjectBugSerializer(serializers.ModelSerializer): 18 | handler = UserSerializer() 19 | tester = UserSerializer() 20 | checker = UserSerializer() 21 | project = ProjectSerializer() 22 | task = ProjectTaskSerializer() 23 | 24 | class Meta: 25 | model = ProjectBug 26 | depth = 1 27 | fields = "__all__" 28 | -------------------------------------------------------------------------------- /project_test/models/project_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:test.py 8 | @date:2017/11/15 11:21 9 | """ 10 | from django.db import models 11 | 12 | 13 | class ProjectTest(models.Model): 14 | """ 15 | 测试用例 16 | """ 17 | project = models.ForeignKey("project.Project", verbose_name=u"项目名称") 18 | name = models.CharField(max_length=50, verbose_name=u'测试名称') 19 | type = models.ForeignKey("ProjectTestType", verbose_name=u"测试类型") 20 | 21 | def __unicode__(self): 22 | return self.name 23 | 24 | def __str__(self): 25 | return self.name 26 | 27 | class Meta: 28 | db_table = "project_test" 29 | verbose_name = u'测试' 30 | verbose_name_plural = u"测试管理" 31 | -------------------------------------------------------------------------------- /project_test/views/project_test_case_history.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_test_case_history.py 8 | @date:2017/11/15 15:08 9 | """ 10 | from rest_framework import status, permissions 11 | from rest_framework.decorators import list_route 12 | from rest_framework import viewsets 13 | from django.db.models import Count 14 | from project_test.models import ProjectTestCaseHistory 15 | from rest_framework.response import Response 16 | from tcis_base.models import User 17 | from ..serializers import * 18 | 19 | 20 | class ProjectTestCaseHistoryViewSet(viewsets.ModelViewSet): 21 | """ 22 | 项目管理 23 | """ 24 | queryset = ProjectTestCaseHistory.objects.all() 25 | serializer_class = ProjectTestCaseHistorySerializer -------------------------------------------------------------------------------- /manage.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import sys 4 | 5 | if __name__ == "__main__": 6 | os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tcis.settings") 7 | try: 8 | from django.core.management import execute_from_command_line 9 | except ImportError: 10 | # The above import may fail for some other reason. Ensure that the 11 | # issue is really that Django is missing to avoid masking other 12 | # exceptions on Python 2. 13 | try: 14 | import django 15 | except ImportError: 16 | raise ImportError( 17 | "Couldn't import Django. Are you sure it's installed and " 18 | "available on your PYTHONPATH environment variable? Did you " 19 | "forget to activate a virtual environment?" 20 | ) 21 | raise 22 | execute_from_command_line(sys.argv) 23 | -------------------------------------------------------------------------------- /tcis_base/models/department.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:department.py 8 | @date:2017/11/8 10:17 9 | """ 10 | from django.db import models 11 | 12 | 13 | class Department(models.Model): 14 | """ 15 | 部门管理 16 | """ 17 | name = models.CharField(max_length=20, verbose_name=u"部门", null=False) 18 | parent = models.ForeignKey('self', verbose_name=u"上级部门", null=True, blank=True) 19 | charge = models.ForeignKey('User', related_name='charge', verbose_name=u'负责人', null=True, blank=True) 20 | description = models.TextField(verbose_name=u"部门职责",null=True, blank=True) 21 | 22 | def __unicode__(self): 23 | return self.name 24 | 25 | def __str__(self): 26 | return self.name 27 | 28 | class Meta: 29 | verbose_name = u'部门' 30 | verbose_name_plural = u'部门管理' -------------------------------------------------------------------------------- /project/models/project_task_history.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_task_history.py 8 | @date:2017/11/15 11:27 9 | """ 10 | from django.db import models 11 | 12 | 13 | class ProjectTaskHistory(models.Model): 14 | """ 15 | 任务历史 16 | """ 17 | task = models.ForeignKey("ProjectTask", verbose_name=u"任务") 18 | description = models.TextField(verbose_name=u"任务描述", null=True, blank=True) 19 | user = models.ForeignKey("tcis_base.User", verbose_name=u"修改员") 20 | 21 | def __unicode__(self): 22 | return self.task.name + "(" + self.user.username_zh or self.user.username + ")" 23 | 24 | def __str__(self): 25 | return self.task.name + "(" + self.user.username_zh or self.user.username + ")" 26 | 27 | class Meta: 28 | db_table = "project_task_history" 29 | verbose_name = u'任务历史' 30 | verbose_name_plural = u"任务历史管理" 31 | -------------------------------------------------------------------------------- /tcis_base/models/tcis_meeting.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:tcis_meeting.py 8 | @date:2017/11/15 10:50 9 | """ 10 | from django.db import models 11 | 12 | 13 | class TcisMeeting(models.Model): 14 | """ 15 | 会议 16 | """ 17 | title = models.CharField(max_length=100, verbose_name=u"会议主题") 18 | recorder = models.ForeignKey('User', related_name='recorder', verbose_name=u"记录员", null=True, blank=True) 19 | moderator = models.ForeignKey("User", related_name='moderator', verbose_name=u"主持人",null=True, blank=True) 20 | start_time = models.DateTimeField(verbose_name=u"开始时间") 21 | end_time = models.DateTimeField(verbose_name=u"结束时间") 22 | 23 | def __unicode__(self): 24 | return self.title 25 | 26 | def __str__(self): 27 | return self.title 28 | 29 | class Meta: 30 | verbose_name = u'会议' 31 | verbose_name_plural = u'会议管理' 32 | -------------------------------------------------------------------------------- /web/src/styles/index.scss: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0rem; 3 | } 4 | 5 | .el-aside { 6 | color: #333; 7 | } 8 | 9 | .el-header { 10 | background-color: #B3C0D1; 11 | color: #333; 12 | line-height: 60px; 13 | } 14 | 15 | // 详情页面样式 16 | .form-read-only { 17 | font-size: 0; 18 | } 19 | 20 | .form-read-only label { 21 | width: 80px; 22 | color: #99a9bf; 23 | } 24 | 25 | .form-read-only .el-form-item { 26 | margin-right: 0; 27 | margin-bottom: 0; 28 | width: 272px; 29 | } 30 | 31 | .tree-form-top { 32 | padding-left: 15px; 33 | padding-right: 15px; 34 | padding-bottom: 20px; 35 | } 36 | 37 | .el-select .el-input__inner { 38 | padding-right: 10px; 39 | } 40 | 41 | .form-tab-top-info { 42 | padding-bottom: 5px; 43 | } 44 | 45 | .tcis-tabs { 46 | margin-top: 10px; 47 | } 48 | 49 | .main-content { 50 | border-top: solid #99a9bf; 51 | padding-top: 10px; 52 | } 53 | 54 | .table-btn { 55 | margin: 2px; 56 | } -------------------------------------------------------------------------------- /project_test/models/project_test_case.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:test_case.py 8 | @date:2017/11/14 10:30 9 | """ 10 | 11 | from django.db import models 12 | 13 | 14 | class ProjectTestCase(models.Model): 15 | """ 16 | 测试用例 17 | """ 18 | project = models.ForeignKey("project.Project", verbose_name=u"项目名称") 19 | task = models.ForeignKey("project.ProjectTask", verbose_name=u"项目任务") 20 | test = models.ForeignKey("ProjectTest", verbose_name=u"测试") 21 | name = models.CharField(max_length=100, verbose_name=u"测试用例名称") 22 | type = models.ForeignKey("ProjectTestType", verbose_name=u"测试类型") 23 | 24 | def __unicode__(self): 25 | return self.name 26 | 27 | def __str__(self): 28 | return self.name 29 | 30 | class Meta: 31 | db_table = "project_test_case" 32 | verbose_name = u'测试用例' 33 | verbose_name_plural = u"测试用例" 34 | 35 | 36 | -------------------------------------------------------------------------------- /project_test/models/project_test_case_history.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:test_case_history.py 8 | @date:2017/11/15 11:26 9 | """ 10 | 11 | from django.db import models 12 | 13 | 14 | class ProjectTestCaseHistory(models.Model): 15 | """ 16 | 测试用例历史 17 | """ 18 | case = models.ForeignKey("ProjectTestCase", verbose_name=u"测试用例") 19 | description = models.TextField(verbose_name=u"任务描述", null=True, blank=True) 20 | user = models.ForeignKey("tcis_base.User", verbose_name=u"修改员") 21 | 22 | def __unicode__(self): 23 | return self.case.name + "(" + self.user.username_zh or self.user.username + ")" 24 | 25 | def __str__(self): 26 | return self.case.name + "(" + self.user.username_zh or self.user.username + ")" 27 | 28 | class Meta: 29 | db_table = "project_test_case_history" 30 | verbose_name = u'测试用例历史' 31 | verbose_name_plural = u"测试用例历史管理" 32 | 33 | -------------------------------------------------------------------------------- /web/src/pages/common/tcis_select.vue: -------------------------------------------------------------------------------- 1 | 13 | 29 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /tcis_base/models/meeting_member.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:meeting_member.py 8 | @date:2017/11/15 11:02 9 | """ 10 | from django.db import models 11 | 12 | 13 | class MeetingMember(models.Model): 14 | """ 15 | 参会人 16 | """ 17 | STATES = ( 18 | ('draft', u'通知'), 19 | ('confirm', u"已知"), 20 | ('done', u"总结确认") 21 | ) 22 | meeting = models.ForeignKey('TcisMeeting', related_name='meeting', verbose_name=u"会议") 23 | user = models.ForeignKey("User", related_name='user', verbose_name=u"参会人") 24 | state = models.CharField(max_length=20, verbose_name=u"状态", choices=STATES, default='draft') 25 | 26 | def __unicode__(self): 27 | return self.meeting.name + "(" + self.user.name + ")" 28 | 29 | def __str__(self): 30 | return self.meeting.name + "(" + self.user.name + ")" 31 | 32 | class Meta: 33 | verbose_name = u'参会人' 34 | verbose_name_plural = u'参会人管理' 35 | -------------------------------------------------------------------------------- /project/models/project_member.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_member.py 8 | @date:2017/11/8 10:59 9 | """ 10 | 11 | from django.db import models 12 | 13 | 14 | class ProjectMember(models.Model): 15 | """ 16 | 项目成员 17 | """ 18 | project = models.ForeignKey("Project", related_name="members", verbose_name=u"项目") 19 | member = models.ForeignKey("tcis_base.User", verbose_name=u"项目成员") 20 | position = models.ForeignKey('tcis_base.Position', verbose_name=u"职位", null=True, blank=True) 21 | active = models.BooleanField(default=True, verbose_name=u"是否有效") 22 | 23 | def __unicode__(self): 24 | return self.project.name + ":" + self.member.username_zh 25 | 26 | def __str__(self): 27 | return self.project.name + ":" + self.member.username_zh 28 | 29 | class Meta: 30 | unique_together = [("project", "member")] 31 | db_table = "project_member" 32 | verbose_name = u'项目成员' 33 | verbose_name_plural = u"项目成员管理" 34 | -------------------------------------------------------------------------------- /tcis_base/models/user.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:user.py 8 | @date:2017/11/8 9:58 9 | """ 10 | 11 | from django.db import models 12 | from django.contrib.auth.models import AbstractUser 13 | 14 | 15 | class User(AbstractUser): 16 | """ 17 | 用户信息扩展 18 | """ 19 | mobile = models.CharField(max_length=20, verbose_name=u'电话', null=True, blank=True, unique=True, default='') 20 | short_phone = models.CharField(max_length=10, verbose_name=u'短号', null=True, blank=True, default='') 21 | username_zh = models.CharField(max_length=20, verbose_name=u'中文名称', null=True, blank=True, default='') 22 | department = models.ForeignKey('Department', verbose_name=u'部门', null=True, blank=True) 23 | position = models.ForeignKey("Position", verbose_name=u"职位", null=True, blank=True) 24 | 25 | def __unicode__(self): 26 | return self.username_zh or self.username 27 | 28 | def __str__(self): 29 | return self.username_zh or self.username 30 | 31 | class Meta: 32 | verbose_name = u'用户' 33 | verbose_name_plural = u'用户管理' 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /static/js/12.b1b737b799e9a743298f.js: -------------------------------------------------------------------------------- 1 | webpackJsonp([12],{"0MuP":function(e,n,t){n=e.exports=t("FZ+f")(!0),n.push([e.i,"#page-404[data-v-098261dd]{-webkit-box-pack:center center;-ms-flex-pack:center center;justify-content:center center}","",{version:3,sources:["F:/selenium_work/tcis/web/src/pages/common/page_404.vue"],names:[],mappings:"AACA,2BACE,+BAAgC,AAC5B,4BAA6B,AACzB,6BAA+B,CACxC",file:"page_404.vue",sourcesContent:["\n#page-404[data-v-098261dd] {\n -webkit-box-pack: center center;\n -ms-flex-pack: center center;\n justify-content: center center;\n}\n"],sourceRoot:""}])},"5nwg":function(e,n){e.exports={render:function(){var e=this,n=e.$createElement;e._self._c;return e._m(0)},staticRenderFns:[function(){var e=this,n=e.$createElement,t=e._self._c||n;return t("div",{attrs:{id:"page-404"}},[t("img",{attrs:{src:"@/assets/page_404.jpg",alt:"page not found"}})])}]}},ImMB:function(e,n,t){function r(e){t("mlER")}var c=t("VU/8")(null,t("5nwg"),r,"data-v-098261dd",null);e.exports=c.exports},mlER:function(e,n,t){var r=t("0MuP");"string"==typeof r&&(r=[[e.i,r,""]]),r.locals&&(e.exports=r.locals);t("rjj0")("1b09a3f3",r,!0)}}); 2 | //# sourceMappingURL=12.b1b737b799e9a743298f.js.map -------------------------------------------------------------------------------- /project/serializers/project.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project.py 8 | @date:2017/11/9 10:20 9 | """ 10 | from rest_framework import serializers 11 | from ..models import Project 12 | from tcis_base.serializers import UserSerializer 13 | import datetime 14 | 15 | 16 | class ProjectSerializer(serializers.ModelSerializer): 17 | manager = UserSerializer() 18 | percentage = serializers.SerializerMethodField(read_only=True) 19 | parent_left = serializers.IntegerField(read_only=True) 20 | parent_right = serializers.IntegerField(read_only=True) 21 | 22 | 23 | def get_percentage(self, obj): 24 | """ 25 | 获得时间进度百分比 26 | :param obj: 27 | :return: 28 | """ 29 | percentage = 0 30 | if obj.start_date and obj.end_date: 31 | all_days = (obj.end_date - obj.start_date).days 32 | past_days = (datetime.date.today() - obj.start_date).days 33 | percentage = int(past_days * 100 / all_days) 34 | return percentage 35 | 36 | class Meta: 37 | model = Project 38 | depth = 2 39 | fields = "__all__" 40 | 41 | 42 | -------------------------------------------------------------------------------- /project/views/project_task_member.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_task.py 8 | @date:2017/11/10 14:15 9 | """ 10 | from rest_framework import viewsets 11 | from ..models import ProjectMember,Project 12 | from ..serializers import * 13 | 14 | 15 | class ProjectMemberViewSet(viewsets.ModelViewSet): 16 | """ 17 | 项目管理 18 | """ 19 | queryset = ProjectMember.objects.all() 20 | serializer_class = ProjectMemberSerializer 21 | 22 | def get_queryset(self): 23 | """ 24 | 过滤 25 | :return: 26 | """ 27 | check_child = self.request.query_params.get("check_child") 28 | project_id = self.request.query_params.get("project_id") 29 | project_ids = [project_id] 30 | if check_child == 'true': 31 | project = Project.objects.get(id=project_id) 32 | projects = Project.objects.filter(parent_left__gte=project.parent_left, parent_right__lte=project.parent_right) 33 | project_ids = [line.id for line in projects] 34 | 35 | self.queryset = self.queryset.filter(project_id__in=project_ids) 36 | return self.queryset 37 | 38 | -------------------------------------------------------------------------------- /web/src/pages/common/form_top.vue: -------------------------------------------------------------------------------- 1 | 9 | 25 | 32 | -------------------------------------------------------------------------------- /web/src/utils/local_store.js: -------------------------------------------------------------------------------- 1 | import { 2 | db_prefix 3 | } from 'config/settings'; 4 | 5 | class LocalStore { 6 | constructor() { 7 | this.localStore = window.localStorage; 8 | this.prefix = db_prefix; 9 | } 10 | set(key, value, fn) { 11 | try { 12 | value = JSON.stringify(value); 13 | } catch (e) { 14 | value = value; 15 | } 16 | 17 | this.localStore.setItem(this.prefix + key, value); 18 | 19 | fn && fn(); 20 | } 21 | get(key, fn) { 22 | if (!key) { 23 | throw new Error('没有找到key。'); 24 | return; 25 | } 26 | if (typeof key === 'object') { 27 | throw new Error('key不能是一个对象。'); 28 | return; 29 | } 30 | var value = this.localStore.getItem(this.prefix + key); 31 | if (value !== null) { 32 | try { 33 | value = JSON.parse(value); 34 | } catch (e) { 35 | value = value; 36 | } 37 | } 38 | 39 | return value; 40 | } 41 | remove(key) { 42 | this.localStore.removeItem(this.prefix + key); 43 | } 44 | } 45 | const localStore = new LocalStore(); 46 | export default localStore 47 | -------------------------------------------------------------------------------- /project_test/migrations/0003_auto_20171115_1200.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.7 on 2017-11-15 04:00 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('project_test', '0002_auto_20171115_1151'), 12 | ] 13 | 14 | operations = [ 15 | migrations.AlterModelOptions( 16 | name='test', 17 | options={'verbose_name': '测试', 'verbose_name_plural': '测试管理'}, 18 | ), 19 | migrations.AlterModelOptions( 20 | name='testcase', 21 | options={'verbose_name': '测试用例', 'verbose_name_plural': '测试用例'}, 22 | ), 23 | migrations.AlterModelOptions( 24 | name='testtype', 25 | options={'verbose_name': '测试类型', 'verbose_name_plural': '测试类型'}, 26 | ), 27 | migrations.AlterModelTable( 28 | name='test', 29 | table='test', 30 | ), 31 | migrations.AlterModelTable( 32 | name='testcase', 33 | table='test_case', 34 | ), 35 | migrations.AlterModelTable( 36 | name='testtype', 37 | table='test_type', 38 | ), 39 | ] 40 | -------------------------------------------------------------------------------- /static/js/18.2ea16126bf605bbc7af2.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///static/js/18.2ea16126bf605bbc7af2.js","webpack:///./src/pages/project/project_task_detail_home.vue"],"names":["webpackJsonp","hFY9","module","exports","__webpack_require__","Component"],"mappings":"AAAAA,cAAc,KAERC,KACA,SAAUC,EAAQC,EAASC,GCHjC,GAAAC,GAAAD,EAAA,QAEA,KAEA,KAEA,KAEA,KAEA,KAGAF,GAAAC,QAAAE,EAAAF","file":"static/js/18.2ea16126bf605bbc7af2.js","sourcesContent":["webpackJsonp([18],{\n\n/***/ \"hFY9\":\n/***/ (function(module, exports, __webpack_require__) {\n\nvar Component = __webpack_require__(\"VU/8\")(\n /* script */\n null,\n /* template */\n null,\n /* styles */\n null,\n /* scopeId */\n null,\n /* moduleIdentifier (server only) */\n null\n)\n\nmodule.exports = Component.exports\n\n\n/***/ })\n\n});\n\n\n// WEBPACK FOOTER //\n// static/js/18.2ea16126bf605bbc7af2.js","var Component = require(\"!../../../node_modules/vue-loader/lib/component-normalizer\")(\n /* script */\n null,\n /* template */\n null,\n /* styles */\n null,\n /* scopeId */\n null,\n /* moduleIdentifier (server only) */\n null\n)\n\nmodule.exports = Component.exports\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/pages/project/project_task_detail_home.vue\n// module id = hFY9\n// module chunks = 18"],"sourceRoot":""} -------------------------------------------------------------------------------- /web/src/pages/system/group/group_info.vue: -------------------------------------------------------------------------------- 1 | 19 | 34 | 37 | -------------------------------------------------------------------------------- /static/js/17.049d493d51aa03865805.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///static/js/17.049d493d51aa03865805.js","webpack:///./src/pages/project_bug/project_bug_detail_home.vue"],"names":["webpackJsonp","wRKD","module","exports","__webpack_require__","Component"],"mappings":"AAAAA,cAAc,KAERC,KACA,SAAUC,EAAQC,EAASC,GCHjC,GAAAC,GAAAD,EAAA,QAEA,KAEA,KAEA,KAEA,KAEA,KAGAF,GAAAC,QAAAE,EAAAF","file":"static/js/17.049d493d51aa03865805.js","sourcesContent":["webpackJsonp([17],{\n\n/***/ \"wRKD\":\n/***/ (function(module, exports, __webpack_require__) {\n\nvar Component = __webpack_require__(\"VU/8\")(\n /* script */\n null,\n /* template */\n null,\n /* styles */\n null,\n /* scopeId */\n null,\n /* moduleIdentifier (server only) */\n null\n)\n\nmodule.exports = Component.exports\n\n\n/***/ })\n\n});\n\n\n// WEBPACK FOOTER //\n// static/js/17.049d493d51aa03865805.js","var Component = require(\"!../../../node_modules/vue-loader/lib/component-normalizer\")(\n /* script */\n null,\n /* template */\n null,\n /* styles */\n null,\n /* scopeId */\n null,\n /* moduleIdentifier (server only) */\n null\n)\n\nmodule.exports = Component.exports\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/pages/project_bug/project_bug_detail_home.vue\n// module id = wRKD\n// module chunks = 17"],"sourceRoot":""} -------------------------------------------------------------------------------- /web/build/build.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | process.env.NODE_ENV = 'production' 5 | 6 | const ora = require('ora') 7 | const rm = require('rimraf') 8 | const path = require('path') 9 | const chalk = require('chalk') 10 | const webpack = require('webpack') 11 | const config = require('../config') 12 | const webpackConfig = require('./webpack.prod.conf') 13 | 14 | const spinner = ora('building for production...') 15 | spinner.start() 16 | 17 | rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { 18 | if (err) throw err 19 | webpack(webpackConfig, function (err, stats) { 20 | spinner.stop() 21 | if (err) throw err 22 | process.stdout.write(stats.toString({ 23 | colors: true, 24 | modules: false, 25 | children: false, 26 | chunks: false, 27 | chunkModules: false 28 | }) + '\n\n') 29 | 30 | if (stats.hasErrors()) { 31 | console.log(chalk.red(' Build failed with errors.\n')) 32 | process.exit(1) 33 | } 34 | 35 | console.log(chalk.cyan(' Build complete.\n')) 36 | console.log(chalk.yellow( 37 | ' Tip: built files are meant to be served over an HTTP server.\n' + 38 | ' Opening index.html over file:// won\'t work.\n' 39 | )) 40 | }) 41 | }) 42 | -------------------------------------------------------------------------------- /static/js/16.16887684d55ab321b8c9.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///static/js/16.16887684d55ab321b8c9.js","webpack:///./src/pages/project_test/project_test_detail_home.vue"],"names":["webpackJsonp","A7zi","module","exports","__webpack_require__","Component"],"mappings":"AAAAA,cAAc,KAERC,KACA,SAAUC,EAAQC,EAASC,GCHjC,GAAAC,GAAAD,EAAA,QAEA,KAEA,KAEA,KAEA,KAEA,KAGAF,GAAAC,QAAAE,EAAAF","file":"static/js/16.16887684d55ab321b8c9.js","sourcesContent":["webpackJsonp([16],{\n\n/***/ \"A7zi\":\n/***/ (function(module, exports, __webpack_require__) {\n\nvar Component = __webpack_require__(\"VU/8\")(\n /* script */\n null,\n /* template */\n null,\n /* styles */\n null,\n /* scopeId */\n null,\n /* moduleIdentifier (server only) */\n null\n)\n\nmodule.exports = Component.exports\n\n\n/***/ })\n\n});\n\n\n// WEBPACK FOOTER //\n// static/js/16.16887684d55ab321b8c9.js","var Component = require(\"!../../../node_modules/vue-loader/lib/component-normalizer\")(\n /* script */\n null,\n /* template */\n null,\n /* styles */\n null,\n /* scopeId */\n null,\n /* moduleIdentifier (server only) */\n null\n)\n\nmodule.exports = Component.exports\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/pages/project_test/project_test_detail_home.vue\n// module id = A7zi\n// module chunks = 16"],"sourceRoot":""} -------------------------------------------------------------------------------- /web/src/pages/common/pagination.vue: -------------------------------------------------------------------------------- 1 | 14 | 35 | 41 | -------------------------------------------------------------------------------- /project/admin/project_task.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_task.py 8 | @date:2017/11/9 16:23 9 | """ 10 | from django.contrib import admin 11 | from ..models import ProjectTask 12 | 13 | 14 | @admin.register(ProjectTask) 15 | class ProjectTaskAdmin(admin.ModelAdmin): 16 | """ 17 | 项目管理后台 18 | """ 19 | search_fields = ["project", "name", "parent", "active", "handler", "state"] 20 | list_display = ["name", "project", "parent", "active", "handler", "state","start_time","end_time", 'real_end_time'] 21 | list_filter = ['project', 'parent', "active", "handler", "state"] 22 | 23 | actions = ['set_disable', 'set_active'] 24 | 25 | def set_disable(self, request, queryset): 26 | """ 27 | 设置项目任务无效 28 | :param request: 29 | :param queryset: 30 | :return: 31 | """ 32 | queryset.update(is_active=False) 33 | 34 | set_disable.short_description = u'设置项目任务无效' 35 | 36 | def set_active(self, request, queryset): 37 | """ 38 | 设置项目任务有效 39 | :param request: 40 | :param queryset: 41 | :return: 42 | """ 43 | queryset.update(is_active=True) 44 | 45 | set_active.short_description = u'设置项目任务有效' 46 | 47 | 48 | -------------------------------------------------------------------------------- /web/src/pages/system/permission/permission_list.vue: -------------------------------------------------------------------------------- 1 | 29 | 46 | -------------------------------------------------------------------------------- /web/src/pages/system/group/group_list.vue: -------------------------------------------------------------------------------- 1 | 27 | 43 | -------------------------------------------------------------------------------- /project_bug/migrations/0003_auto_20171115_1324.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.7 on 2017-11-15 05:24 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | import django.db.models.deletion 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | dependencies = [ 13 | ('project_bug', '0002_auto_20171115_1151'), 14 | ] 15 | 16 | operations = [ 17 | migrations.AlterField( 18 | model_name='projectbug', 19 | name='checker', 20 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='checker', to=settings.AUTH_USER_MODEL, verbose_name='验证员'), 21 | ), 22 | migrations.AlterField( 23 | model_name='projectbug', 24 | name='handler', 25 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='handler', to=settings.AUTH_USER_MODEL, verbose_name='处理员'), 26 | ), 27 | migrations.AlterField( 28 | model_name='projectbug', 29 | name='tester', 30 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='tester', to=settings.AUTH_USER_MODEL, verbose_name='测试员'), 31 | ), 32 | ] 33 | -------------------------------------------------------------------------------- /web/build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const utils = require('./utils') 3 | const webpack = require('webpack') 4 | const config = require('../config') 5 | const merge = require('webpack-merge') 6 | const baseWebpackConfig = require('./webpack.base.conf') 7 | const HtmlWebpackPlugin = require('html-webpack-plugin') 8 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') 9 | 10 | // add hot-reload related code to entry chunks 11 | Object.keys(baseWebpackConfig.entry).forEach(function (name) { 12 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 13 | }) 14 | 15 | module.exports = merge(baseWebpackConfig, { 16 | module: { 17 | rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) 18 | }, 19 | // cheap-module-eval-source-map is faster for development 20 | devtool: '#cheap-module-eval-source-map', 21 | plugins: [ 22 | new webpack.DefinePlugin({ 23 | 'process.env': config.dev.env 24 | }), 25 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 26 | new webpack.HotModuleReplacementPlugin(), 27 | new webpack.NoEmitOnErrorsPlugin(), 28 | // https://github.com/ampedandwired/html-webpack-plugin 29 | new HtmlWebpackPlugin({ 30 | filename: 'index.html', 31 | template: 'index.html', 32 | inject: true 33 | }), 34 | new FriendlyErrorsPlugin() 35 | ] 36 | }) 37 | -------------------------------------------------------------------------------- /web/src/main.js: -------------------------------------------------------------------------------- 1 | import babelpolyfill from 'babel-polyfill' 2 | import Vue from 'vue' 3 | import App from './App' 4 | import router from './router'; 5 | import ElementUI from 'element-ui' 6 | import 'element-ui/lib/theme-chalk/index.css' 7 | import store from './store' 8 | import Vuex from 'vuex' 9 | 10 | import NProgress from 'nprogress' 11 | import 'nprogress/nprogress.css' 12 | import localStore from '@/utils/local_store'; 13 | import stringTimeFormat from '@/utils/filters'; 14 | import axios from 'axios'; 15 | const XSRFCOOKIENAME = 'csrftoken'; 16 | const XSRFHEADERNAME = 'X_CSRFTOKEN'; 17 | axios.defaults.xsrfCookieName = XSRFCOOKIENAME; 18 | axios.defaults.xsrfHeaderName = XSRFHEADERNAME; 19 | 20 | Vue.prototype.$ajax = axios; 21 | 22 | 23 | import echarts from 'echarts'; 24 | import "@/styles/index.scss"; 25 | Vue.prototype.$echarts = echarts; 26 | Vue.filter('stringTimeFormat', stringTimeFormat); 27 | 28 | Vue.use(ElementUI) 29 | 30 | Vue.use(Vuex) 31 | 32 | router.beforeEach((to, from, next) => { 33 | // NProgress.start(); 34 | if (to.path == '/login') { 35 | localStore.remove('userinfo'); 36 | next(); 37 | } else { 38 | let user = JSON.parse(localStore.get('userinfo')); 39 | if (!user) { 40 | next({ path: '/login' }); 41 | } else { 42 | next(); 43 | } 44 | } 45 | }); 46 | 47 | new Vue({ 48 | router, 49 | store, 50 | render: h => h(App) 51 | }).$mount('#app') -------------------------------------------------------------------------------- /project_bug/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.7 on 2017-11-15 03:51 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | initial = True 11 | 12 | dependencies = [ 13 | ] 14 | 15 | operations = [ 16 | migrations.CreateModel( 17 | name='ProjectBug', 18 | fields=[ 19 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 20 | ('name', models.CharField(max_length=50, verbose_name='Bug名称')), 21 | ('description', models.TextField(verbose_name='Bug描述')), 22 | ('state', models.CharField(choices=[('draft', '草稿'), ('confirm', '已确认'), ('appointed', '已指派'), ('processing', '处理中'), ('refuse', '已拒绝'), ('hold', '挂起'), ('solved', '已解决'), ('done', '完成'), ('close', '关闭')], default='draft', max_length=10, verbose_name='状态')), 23 | ('level', models.IntegerField(choices=[(1, '致命'), (2, '重大'), (3, '次要'), (4, '一般'), (5, '建议')], default=4, verbose_name='级别')), 24 | ('open_times', models.IntegerField(default=1, verbose_name='打开次数')), 25 | ], 26 | options={ 27 | 'verbose_name': '项目Bug', 28 | 'verbose_name_plural': '项目Bug管理', 29 | 'db_table': 'project_bug', 30 | }, 31 | ), 32 | ] 33 | -------------------------------------------------------------------------------- /project_test/migrations/0004_auto_20171115_1324.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.7 on 2017-11-15 05:24 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations 6 | 7 | 8 | class Migration(migrations.Migration): 9 | 10 | dependencies = [ 11 | ('project_test', '0003_auto_20171115_1200'), 12 | ] 13 | 14 | operations = [ 15 | migrations.RenameModel( 16 | old_name='Test', 17 | new_name='ProjectTest', 18 | ), 19 | migrations.RenameModel( 20 | old_name='TestCase', 21 | new_name='ProjectTestCase', 22 | ), 23 | migrations.RenameModel( 24 | old_name='TestCaseHistory', 25 | new_name='ProjectTestCaseHistory', 26 | ), 27 | migrations.RenameModel( 28 | old_name='TestType', 29 | new_name='ProjectTestType', 30 | ), 31 | migrations.AlterModelTable( 32 | name='projecttest', 33 | table='project_test', 34 | ), 35 | migrations.AlterModelTable( 36 | name='projecttestcase', 37 | table='project_test_case', 38 | ), 39 | migrations.AlterModelTable( 40 | name='projecttestcasehistory', 41 | table='project_test_case_history', 42 | ), 43 | migrations.AlterModelTable( 44 | name='projecttesttype', 45 | table='project_test_type', 46 | ), 47 | ] 48 | -------------------------------------------------------------------------------- /web/build/check-versions.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const chalk = require('chalk') 3 | const semver = require('semver') 4 | const packageConfig = require('../package.json') 5 | const shell = require('shelljs') 6 | function exec (cmd) { 7 | return require('child_process').execSync(cmd).toString().trim() 8 | } 9 | 10 | const versionRequirements = [ 11 | { 12 | name: 'node', 13 | currentVersion: semver.clean(process.version), 14 | versionRequirement: packageConfig.engines.node 15 | } 16 | ] 17 | 18 | if (shell.which('npm')) { 19 | versionRequirements.push({ 20 | name: 'npm', 21 | currentVersion: exec('npm --version'), 22 | versionRequirement: packageConfig.engines.npm 23 | }) 24 | } 25 | 26 | module.exports = function () { 27 | const warnings = [] 28 | for (let i = 0; i < versionRequirements.length; i++) { 29 | const mod = versionRequirements[i] 30 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 31 | warnings.push(mod.name + ': ' + 32 | chalk.red(mod.currentVersion) + ' should be ' + 33 | chalk.green(mod.versionRequirement) 34 | ) 35 | } 36 | } 37 | 38 | if (warnings.length) { 39 | console.log('') 40 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 41 | console.log() 42 | for (let i = 0; i < warnings.length; i++) { 43 | const warning = warnings[i] 44 | console.log(' ' + warning) 45 | } 46 | console.log() 47 | process.exit(1) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tcis_base/admin/user.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:user.py 8 | @date:2017/11/9 9:31 9 | """ 10 | from django.contrib import admin 11 | 12 | from ..models import User 13 | 14 | 15 | @admin.register(User) 16 | class UserAdmin(admin.ModelAdmin): 17 | """ 18 | 用户后台信息管理 19 | """ 20 | search_fields = ['username', 'mobile', 'department', 'position'] 21 | list_display = ['username', 'username_zh', 'department', 'position', 'mobile', 'is_active'] 22 | list_filter = ['department', 'position'] 23 | 24 | fieldsets = [ 25 | (u'基本信息', { 26 | 'fields': ['username', 'username_zh', 'is_active', 'email', 'mobile'], 27 | }), 28 | (u'部门信息', { 29 | 'fields': ['department', 'position'], 30 | }), 31 | (u"权限信息", { 32 | 'fields': ["groups"], 33 | }) 34 | ] 35 | 36 | actions = ['set_disable', 'set_active'] 37 | 38 | def set_disable(self, request, queryset): 39 | """ 40 | 设置用户无效 41 | :param request: 42 | :param queryset: 43 | :return: 44 | """ 45 | queryset.update(is_active=False) 46 | 47 | set_disable.short_description = u'设置用户无效' 48 | 49 | def set_active(self, request, queryset): 50 | """ 51 | 设置用户有效 52 | :param request: 53 | :param queryset: 54 | :return: 55 | """ 56 | queryset.update(is_active=True) 57 | 58 | set_active.short_description = u'设置用户有效' -------------------------------------------------------------------------------- /web/src/server_address.js: -------------------------------------------------------------------------------- 1 | // 服务器端地址 2 | 3 | export const SERVER_USER = "/user/"; //用户 4 | export const SERVER_USER_LOGIN = "/user/login/"; //用户登录 5 | export const SERVER_USER_LOGOUT = "/user/logout/"; //用户登出 6 | export const SERVER_USER_RESET_PASSWORD = "/user/reset_password/"; //重置密码 7 | export const SERVER_USER_ACTIVE = '/user/user_active/'; // 无效用户 8 | export const SERVER_GROUP = "/group/"; //用户组 9 | export const SERVER_PERMISSION = "/permission/"; //用户权限 10 | export const SERVER_PERMISSION_ALL = "/permission/get_all_permission/"; //所有用户权限 11 | export const SERVER_PERMISSION_TRANSLATE = "/permission/translate_all_permission/"; //权限翻译 12 | 13 | export const SERVER_PROJECT = "/project/project/"; //项目 14 | export const SERVER_PROJECT_ALL = "/project/project/get_all_project/"; //所有项目 15 | export const SERVER_PROJECT_TASK = "/project/project_task/"; //项目任务 16 | export const SERVER_PROJECT_TASK_INFO = '/project/project_task/project_task_kanban/'; //项目任务信息 17 | export const SERVER_PROJECT_TASK_GANTT = '/project/project_task/project_task_gantt/'; //项目任务甘特图 18 | export const SERVER_PROJECT_MEMBER = "/project/project_member/"; //项目组成员 19 | export const SERVER_PROJECT_BUG = "/project_bug/project_bug/"; //项目bug 20 | export const SERVER_PROJECT_BUG_INFO = "/project_bug/project_bug/project_bug_kanban/"; //项目bug信息 21 | 22 | export const SERVER_PROJECT_TEST = "/project_test/project_test/"; //项目test 23 | export const SERVER_PROJECT_TEST_INFO = "/project_test/project_test/project_test_kanban/"; //项目test信息 24 | export const SERVER_PROJECT_TEST_TYPE = "/project_test/project_test_type/"; //项目test类型 -------------------------------------------------------------------------------- /web/src/pages/system/group/group_card.vue: -------------------------------------------------------------------------------- 1 | 15 | 40 | 46 | 47 | -------------------------------------------------------------------------------- /web/src/pages/system/group/group_kanban.vue: -------------------------------------------------------------------------------- 1 | 6 | 50 | -------------------------------------------------------------------------------- /project/models/project.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project.py 8 | @date:2017/11/8 10:34 9 | """ 10 | from django.db import models 11 | from common import parent_tree 12 | 13 | 14 | class Project(models.Model): 15 | """ 16 | 项目表 17 | """ 18 | name = models.CharField(max_length=50, verbose_name=u'项目名称', unique=True, null=False) 19 | active = models.BooleanField(default=True, verbose_name=u"是否有效") 20 | start_date = models.DateField(verbose_name=u"开始时间", null=True, blank=True) 21 | end_date = models.DateField(verbose_name=u"结束时间", null=True, blank=True) 22 | manager = models.ForeignKey('tcis_base.User', verbose_name=u"项目经理",null=True, blank=True) 23 | parent_left = models.IntegerField(verbose_name=u"左", unique=True, null=True, blank=True) 24 | parent_right = models.IntegerField(verbose_name=u"右", unique=True, null=True, blank=True) 25 | parent = models.ForeignKey("self", related_name="childs", verbose_name=u"上级项目", null=True, blank=True) 26 | description = models.TextField(verbose_name=u"项目描述", null=True, blank=True) 27 | 28 | def __unicode__(self): 29 | return self.name 30 | 31 | def __str__(self): 32 | return self.name 33 | 34 | class Meta: 35 | db_table = "project" 36 | verbose_name = u'项目' 37 | verbose_name_plural = u"项目管理" 38 | 39 | def save(self, force_insert=False, force_update=False, using=None, 40 | update_fields=None): 41 | obj = parent_tree(self, Project) 42 | return super(Project, obj).save(force_insert, force_update, using, update_fields) 43 | -------------------------------------------------------------------------------- /project_test/views/project_test.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_test.py 8 | @date:2017/11/10 14:15 9 | """ 10 | from rest_framework import status, permissions 11 | from rest_framework.decorators import list_route 12 | from rest_framework import viewsets 13 | from django.db.models import Count 14 | from project.models import Project 15 | from project_test.models import ProjectTest 16 | from rest_framework.response import Response 17 | from tcis_base.models import User 18 | from ..serializers import * 19 | 20 | 21 | class ProjectTestViewSet(viewsets.ModelViewSet): 22 | """ 23 | 项目管理 24 | """ 25 | queryset = ProjectTest.objects.all() 26 | serializer_class = ProjectTestSerializer 27 | 28 | def get_queryset(self): 29 | project_id = self.request.query_params.get("project_id") 30 | type_id = self.request.query_params.get("type_id") 31 | if project_id: 32 | self.queryset = self.queryset.filter(project_id=project_id) 33 | if type_id: 34 | self.queryset = self.queryset.filter(type_id=type_id) 35 | 36 | return self.queryset 37 | 38 | @list_route(["get"], 39 | permission_classes=[permissions.AllowAny]) 40 | def project_test_kanban(self, request): 41 | projects = Project.objects.all() 42 | project_list = [] 43 | for project in projects: 44 | project_list.append({ 45 | "id": project.id, 46 | "name": project.name 47 | }) 48 | return Response(project_list, status=status.HTTP_200_OK) 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /project/views/project.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project.py 8 | @date:2017/11/8 16:50 9 | """ 10 | from rest_framework import viewsets 11 | from ..models import Project 12 | from ..serializers import * 13 | from rest_framework.decorators import list_route 14 | from rest_framework import status, permissions 15 | from rest_framework.response import Response 16 | 17 | 18 | class ProjectViewSet(viewsets.ModelViewSet): 19 | """ 20 | 项目管理 21 | """ 22 | queryset = Project.objects.all() 23 | serializer_class = ProjectSerializer 24 | 25 | def get_queryset(self): 26 | """ 27 | 过滤 28 | :return: 29 | """ 30 | check_child = self.request.query_params.get("check_child") 31 | project_id = self.request.query_params.get("project_id") 32 | if project_id: 33 | if check_child == "true": 34 | parent = Project.objects.get(id=project_id) 35 | self.queryset = self.queryset.filter(parent_left__gt=parent.parent_left, 36 | parent_right__lt=parent.parent_right) 37 | return self.queryset 38 | 39 | @list_route(["get"], 40 | permission_classes=[permissions.AllowAny]) 41 | def get_all_project(self, request): 42 | projects = Project.objects.all() 43 | project_list = [] 44 | for project in projects: 45 | project_list.append({ 46 | "id": project.id, 47 | "name": project.name 48 | }) 49 | return Response(project_list, status=status.HTTP_200_OK) 50 | 51 | -------------------------------------------------------------------------------- /tcis_base/views/permission.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:permission.py 8 | @date:2017/11/15 17:55 9 | """ 10 | from rest_framework import viewsets 11 | from django.contrib.auth.models import Permission 12 | from ..serializers import PermissionSerializer 13 | from rest_framework import status, permissions 14 | from rest_framework.response import Response 15 | from rest_framework.decorators import list_route 16 | 17 | 18 | class PermissionViewSet(viewsets.ModelViewSet): 19 | """ 20 | 用户权限 21 | """ 22 | queryset = Permission.objects.all() 23 | serializer_class = PermissionSerializer 24 | 25 | @list_route(["get"], 26 | permission_classes=[permissions.AllowAny]) 27 | def get_all_permission(self, request): 28 | """ 29 | 过滤 30 | :return: 31 | """ 32 | all_permissions = [] 33 | for line in self.queryset: 34 | all_permissions.append({ 35 | "id": line.id, 36 | "name": line.name 37 | }) 38 | return Response(all_permissions, status=status.HTTP_200_OK) 39 | 40 | @list_route(["get"], 41 | permission_classes=[permissions.AllowAny]) 42 | def translate_all_permission(self, request): 43 | """ 44 | 翻译 45 | :return: 46 | """ 47 | for permission in self.queryset: 48 | permission.name = permission.name.replace("Can add ", u"可创建:") 49 | permission.name = permission.name.replace("Can change ", u"可修改:") 50 | permission.name = permission.name.replace("Can delete ", u"可删除:") 51 | permission.save() 52 | 53 | return Response([], status=status.HTTP_200_OK) 54 | -------------------------------------------------------------------------------- /web/config/index.js: -------------------------------------------------------------------------------- 1 | 2 | 'use strict' 3 | // Template version: 1.1.3 4 | // see http://vuejs-templates.github.io/webpack for documentation. 5 | 6 | const path = require('path') 7 | 8 | module.exports = { 9 | build: { 10 | env: require('./prod.env'), 11 | //index: path.resolve(__dirname, '../dist/index.html'), 12 | //assetsRoot: path.resolve(__dirname, '../dist'), 13 | index: path.resolve(__dirname, '../../templates/index.html'), 14 | assetsRoot: path.resolve(__dirname, '../../'), 15 | assetsSubDirectory: 'static', 16 | assetsPublicPath: '/', 17 | productionSourceMap: true, 18 | // Gzip off by default as many popular static hosts such as 19 | // Surge or Netlify already gzip all static assets for you. 20 | // Before setting to `true`, make sure to: 21 | // npm install --save-dev compression-webpack-plugin 22 | productionGzip: false, 23 | productionGzipExtensions: ['js', 'css'], 24 | // Run the build command with an extra argument to 25 | // View the bundle analyzer report after build finishes: 26 | // `npm run build --report` 27 | // Set to `true` or `false` to always turn it on or off 28 | bundleAnalyzerReport: process.env.npm_config_report 29 | }, 30 | dev: { 31 | env: require('./dev.env'), 32 | port: process.env.PORT || 8080, 33 | autoOpenBrowser: true, 34 | assetsSubDirectory: 'static', 35 | assetsPublicPath: '/', 36 | proxyTable: {}, 37 | // CSS Sourcemaps off by default because relative paths are "buggy" 38 | // with this option, according to the CSS-Loader README 39 | // (https://github.com/webpack/css-loader#sourcemaps) 40 | // In our experience, they generally work as expected, 41 | // just be aware of this issue when enabling this option. 42 | cssSourceMap: false 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /web/src/pages/base/header.vue: -------------------------------------------------------------------------------- 1 | 15 | 50 | 51 | -------------------------------------------------------------------------------- /web/src/pages/project_bug/project_bug_kanban.vue: -------------------------------------------------------------------------------- 1 | 6 | 52 | -------------------------------------------------------------------------------- /project_bug/models/project_bug.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_bug.py 8 | @date:2017/11/8 10:51 9 | """ 10 | 11 | from django.db import models 12 | 13 | 14 | class ProjectBug(models.Model): 15 | """ 16 | 项目bug管理 17 | """ 18 | 19 | STATES = ( 20 | ('draft', u'草稿'), 21 | ('confirm', u"已确认"), 22 | ('appointed', u"已指派"), 23 | ('processing', u"处理中"), 24 | ('refuse', u"已拒绝"), 25 | ('hold', u"挂起"), 26 | ('solved', u"已解决"), 27 | ('done', u"完成"), 28 | ('close', u"关闭") 29 | ) 30 | LEVELS = ( 31 | (1, u"致命"), 32 | (2, u"重大"), 33 | (3, u"次要"), 34 | (4, u"一般"), 35 | (5, u"建议") 36 | ) 37 | project = models.ForeignKey("project.Project", verbose_name=u"项目名称") 38 | task = models.ForeignKey('project.ProjectTask', verbose_name=u"项目任务", null=True, blank=True) 39 | name = models.CharField(max_length=50, verbose_name=u"Bug名称") 40 | description = models.TextField(verbose_name=u"Bug描述") 41 | state = models.CharField(max_length=10, verbose_name=u"状态", choices=STATES, default='draft') 42 | level = models.IntegerField(verbose_name=u"级别", choices=LEVELS, default=4) 43 | tester = models.ForeignKey("tcis_base.User", related_name="tester", verbose_name=u"测试员", null=True, blank=True) 44 | handler = models.ForeignKey("tcis_base.User", related_name="handler", verbose_name=u"处理员", null=True, blank=True) 45 | checker = models.ForeignKey('tcis_base.User', related_name="checker", verbose_name=u"验证员", null=True, blank=True) 46 | open_times = models.IntegerField(verbose_name=u"打开次数", default=1) 47 | 48 | class Meta: 49 | db_table = "project_bug" 50 | verbose_name = u'项目Bug' 51 | verbose_name_plural = u"项目Bug管理" 52 | 53 | -------------------------------------------------------------------------------- /web/src/pages/project/project_task_kanban.vue: -------------------------------------------------------------------------------- 1 | 6 | 52 | -------------------------------------------------------------------------------- /static/js/manifest.56a3f94c7823145ecc26.js: -------------------------------------------------------------------------------- 1 | !function(e){function n(c){if(r[c])return r[c].exports;var t=r[c]={i:c,l:!1,exports:{}};return e[c].call(t.exports,t,t.exports,n),t.l=!0,t.exports}var c=window.webpackJsonp;window.webpackJsonp=function(r,a,o){for(var f,b,i,u=0,d=[];u 2 |
3 | 4 |
5 | 6 | 55 | -------------------------------------------------------------------------------- /project/models/project_task.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:project_task.py 8 | @date:2017/11/8 10:51 9 | """ 10 | from django.db import models 11 | 12 | 13 | class ProjectTask(models.Model): 14 | """ 15 | 项目任务管理 16 | """ 17 | STATES = ( 18 | ('draft', u'草稿'), 19 | ('confirm', u"已确认"), 20 | ('appointed', u"已指派"), 21 | ('processing', u"处理中"), 22 | ('hold', u"挂起"), 23 | ('done', u"完成") 24 | ) 25 | LEVELS = ( 26 | (1, u"非常紧急"), 27 | (2, u"紧急"), 28 | (3, u"一般"), 29 | (4, u"次要"), 30 | ) 31 | 32 | project = models.ForeignKey("Project", verbose_name=u"项目") 33 | type = models.ForeignKey("ProjectTaskType", verbose_name=u"任务类型") 34 | name = models.CharField(max_length=50, verbose_name=u'项目任务名称', null=True) 35 | active = models.BooleanField(default=True, verbose_name=u"是否有效") 36 | description = models.TextField(verbose_name=u"任务描述", null=True, blank=True) 37 | handler = models.ForeignKey('tcis_base.User', verbose_name=u"处理人", null=True, blank=True) 38 | parent = models.ForeignKey('self', verbose_name=u"上级任务", null=True, blank=True) 39 | state = models.CharField(max_length=20, verbose_name=u"状态", choices=STATES, default='draft') 40 | need_time = models.FloatField(verbose_name=u"估计时长(h)", default=1) 41 | start_time = models.DateTimeField(verbose_name=u"开始时间", null=True, blank=True) 42 | end_time = models.DateTimeField(verbose_name=u"计划完成时间", null=True, blank=True) 43 | real_end_time = models.DateTimeField(verbose_name=u"实际完成时间", null=True, blank=True) 44 | level = models.IntegerField(verbose_name=u"级别", choices=LEVELS, default=3) 45 | 46 | def __unicode__(self): 47 | return self.project.name + ":" + self.name 48 | 49 | def __str__(self): 50 | return self.project.name + ":" + self.name 51 | 52 | class Meta: 53 | db_table = "project_task" 54 | verbose_name = u'项目任务' 55 | verbose_name_plural = u"项目任务管理" 56 | -------------------------------------------------------------------------------- /tcis/urls.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """tcis URL Configuration 4 | 5 | The `urlpatterns` list routes URLs to views. For more information please see: 6 | https://docs.djangoproject.com/en/1.11/topics/http/urls/ 7 | Examples: 8 | Function views 9 | 1. Add an import: from my_app import views 10 | 2. Add a URL to urlpatterns: url(r'^$', views.home, name='home') 11 | Class-based views 12 | 1. Add an import: from other_app.views import Home 13 | 2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home') 14 | Including another URLconf 15 | 1. Import the include() function: from django.conf.urls import url, include 16 | 2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls')) 17 | """ 18 | from django.conf import settings 19 | from django.conf.urls import url,include 20 | from django.contrib import admin 21 | from django.conf.urls.static import static 22 | 23 | 24 | urlpatterns = [ 25 | # 系统后台 26 | url(r'^admin/', admin.site.urls), 27 | # 接口 28 | url(r'^auth/', include('rest_framework.urls', namespace='rest_framework')), 29 | # 项目管理 30 | url(r'^project/', include('project.urls', namespace='project', app_name='project manage')), 31 | # 项目bug管理 32 | url(r'^project_bug/', include('project_bug.urls', namespace='project_bug', app_name='project bug manage')), 33 | # 项目持续集成 34 | url(r'^project_ci/', include('project_ci.urls', namespace='project_ci', 35 | app_name='project continuous integration')), 36 | # 项目测试 37 | url(r'^project_test/', include('project_test.urls', namespace='project_test', app_name='project test')), 38 | # 绩效考核 39 | url(r'^performance_appraisal/', include('performance_appraisal.urls', namespace='performance_appraisal', app_name='performance appraisal')), 40 | 41 | # 基础 42 | url(r'', include('tcis_base.urls', namespace='tcis_base', 43 | app_name='test continuous integration system base manage')), 44 | 45 | ] 46 | urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT) 47 | -------------------------------------------------------------------------------- /project_test/migrations/0001_initial.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.7 on 2017-11-15 03:51 3 | from __future__ import unicode_literals 4 | 5 | from django.db import migrations, models 6 | import django.db.models.deletion 7 | 8 | 9 | class Migration(migrations.Migration): 10 | 11 | initial = True 12 | 13 | dependencies = [ 14 | ] 15 | 16 | operations = [ 17 | migrations.CreateModel( 18 | name='Test', 19 | fields=[ 20 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 21 | ('name', models.CharField(max_length=50, verbose_name='测试名称')), 22 | ], 23 | ), 24 | migrations.CreateModel( 25 | name='TestCase', 26 | fields=[ 27 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 28 | ('name', models.CharField(max_length=100, verbose_name='测试用例名称')), 29 | ], 30 | ), 31 | migrations.CreateModel( 32 | name='TestCaseHistory', 33 | fields=[ 34 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 35 | ('description', models.TextField(blank=True, null=True, verbose_name='任务描述')), 36 | ('case', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='project_test.TestCase', verbose_name='测试用例')), 37 | ], 38 | options={ 39 | 'verbose_name': '测试用例历史', 40 | 'verbose_name_plural': '测试用例历史管理', 41 | 'db_table': 'test_case_history', 42 | }, 43 | ), 44 | migrations.CreateModel( 45 | name='TestType', 46 | fields=[ 47 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 48 | ('name', models.CharField(max_length=20, unique=True, verbose_name='测试类型')), 49 | ], 50 | ), 51 | ] 52 | -------------------------------------------------------------------------------- /web/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const utils = require('./utils') 4 | const config = require('../config') 5 | const vueLoaderConfig = require('./vue-loader.conf') 6 | 7 | function resolve (dir) { 8 | return path.join(__dirname, '..', dir) 9 | } 10 | 11 | module.exports = { 12 | entry: { 13 | app: './src/main.js' 14 | }, 15 | output: { 16 | path: config.build.assetsRoot, 17 | filename: '[name].js', 18 | publicPath: process.env.NODE_ENV === 'production' 19 | ? config.build.assetsPublicPath 20 | : config.dev.assetsPublicPath 21 | }, 22 | resolve: { 23 | extensions: ['.js', '.vue', '.json'], 24 | alias: { 25 | 'vue$': 'vue/dist/vue.esm.js', 26 | '@': resolve('src'), 27 | 'utils': path.resolve(__dirname, '../src/utils'), 28 | 'store': path.resolve(__dirname, '../src/store'), 29 | 'router': path.resolve(__dirname, '../src/router'), 30 | 'pages': path.resolve(__dirname, '../src/pages'), 31 | 'config': path.resolve(__dirname, '../src/config'), 32 | } 33 | }, 34 | module: { 35 | rules: [ 36 | { 37 | test: /\.vue$/, 38 | loader: 'vue-loader', 39 | options: vueLoaderConfig 40 | }, 41 | { 42 | test: /\.js$/, 43 | loader: 'babel-loader', 44 | include: [resolve('src'), resolve('test')] 45 | }, 46 | { 47 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 48 | loader: 'url-loader', 49 | options: { 50 | limit: 10000, 51 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 52 | } 53 | }, 54 | { 55 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 56 | loader: 'url-loader', 57 | options: { 58 | limit: 10000, 59 | name: utils.assetsPath('media/[name].[hash:7].[ext]') 60 | } 61 | }, 62 | { 63 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 64 | loader: 'url-loader', 65 | options: { 66 | limit: 10000, 67 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 68 | } 69 | } 70 | ] 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /web/src/pages/project/project_list.vue: -------------------------------------------------------------------------------- 1 | 50 | 66 | -------------------------------------------------------------------------------- /web/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tcis_web", 3 | "version": "1.0.0", 4 | "description": "tcis", 5 | "author": "cloudy <272685110@qq.com>", 6 | "private": true, 7 | "scripts": { 8 | "dev": "node build/dev-server.js", 9 | "start": "npm run dev", 10 | "build": "node build/build.js" 11 | }, 12 | "dependencies": { 13 | "axios": "^0.16.2", 14 | "babel-polyfill": "^6.23.0", 15 | "echarts": "^3.6.2", 16 | "element-ui": "^2.0.3", 17 | "lodash": "^4.17.4", 18 | "nprogress": "^0.2.0", 19 | "vue": "^2.5.2", 20 | "vue-router": "^3.0.1", 21 | "vuex": "^2.3.1" 22 | }, 23 | "devDependencies": { 24 | "autoprefixer": "^6.7.2", 25 | "babel-core": "^6.22.1", 26 | "babel-loader": "^6.2.10", 27 | "babel-plugin-transform-runtime": "^6.22.0", 28 | "babel-preset-env": "^1.3.2", 29 | "babel-preset-stage-2": "^6.22.0", 30 | "babel-register": "^6.22.0", 31 | "chalk": "^1.1.3", 32 | "connect-history-api-fallback": "^1.3.0", 33 | "copy-webpack-plugin": "^4.0.1", 34 | "css-loader": "^0.28.0", 35 | "eventsource-polyfill": "^0.9.6", 36 | "express": "^4.14.1", 37 | "extract-text-webpack-plugin": "^2.0.0", 38 | "file-loader": "^0.11.1", 39 | "friendly-errors-webpack-plugin": "^1.1.3", 40 | "html-webpack-plugin": "^2.28.0", 41 | "http-proxy-middleware": "^0.17.3", 42 | "lodash": "^4.17.4", 43 | "node-sass": "^4.5.3", 44 | "opn": "^4.0.2", 45 | "optimize-css-assets-webpack-plugin": "^1.3.0", 46 | "ora": "^1.2.0", 47 | "rimraf": "^2.6.0", 48 | "sass-loader": "^6.0.6", 49 | "semver": "^5.3.0", 50 | "shelljs": "^0.7.6", 51 | "url-loader": "^0.5.8", 52 | "vue-loader": "^12.1.0", 53 | "vue-style-loader": "^3.0.1", 54 | "vue-template-compiler": "^2.3.3", 55 | "webpack": "^2.6.1", 56 | "webpack-bundle-analyzer": "^2.2.1", 57 | "webpack-dev-middleware": "^1.10.0", 58 | "webpack-hot-middleware": "^2.18.0", 59 | "webpack-merge": "^4.1.0" 60 | }, 61 | "engines": { 62 | "node": ">= 4.0.0", 63 | "npm": ">= 3.0.0" 64 | }, 65 | "browserslist": [ 66 | "> 1%", 67 | "last 2 versions", 68 | "not ie <= 8" 69 | ] 70 | } 71 | -------------------------------------------------------------------------------- /web/src/pages/common/view_switch.vue: -------------------------------------------------------------------------------- 1 | 8 | 58 | 66 | 67 | -------------------------------------------------------------------------------- /web/src/pages/project_bug/project_bug_card.vue: -------------------------------------------------------------------------------- 1 | 23 | 51 | 57 | 58 | -------------------------------------------------------------------------------- /web/src/pages/project_test/project_test_card.vue: -------------------------------------------------------------------------------- 1 | 23 | 51 | 57 | 58 | -------------------------------------------------------------------------------- /web/src/pages/project/project_task_gantt.vue: -------------------------------------------------------------------------------- 1 | 6 | 58 | -------------------------------------------------------------------------------- /web/build/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const path = require('path') 3 | const config = require('../config') 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin') 5 | 6 | exports.assetsPath = function (_path) { 7 | const assetsSubDirectory = process.env.NODE_ENV === 'production' 8 | ? config.build.assetsSubDirectory 9 | : config.dev.assetsSubDirectory 10 | return path.posix.join(assetsSubDirectory, _path) 11 | } 12 | 13 | exports.cssLoaders = function (options) { 14 | options = options || {} 15 | 16 | const cssLoader = { 17 | loader: 'css-loader', 18 | options: { 19 | minimize: process.env.NODE_ENV === 'production', 20 | sourceMap: options.sourceMap 21 | } 22 | } 23 | 24 | // generate loader string to be used with extract text plugin 25 | function generateLoaders (loader, loaderOptions) { 26 | const loaders = [cssLoader] 27 | if (loader) { 28 | loaders.push({ 29 | loader: loader + '-loader', 30 | options: Object.assign({}, loaderOptions, { 31 | sourceMap: options.sourceMap 32 | }) 33 | }) 34 | } 35 | 36 | // Extract CSS when that option is specified 37 | // (which is the case during production build) 38 | if (options.extract) { 39 | return ExtractTextPlugin.extract({ 40 | use: loaders, 41 | fallback: 'vue-style-loader' 42 | }) 43 | } else { 44 | return ['vue-style-loader'].concat(loaders) 45 | } 46 | } 47 | 48 | // https://vue-loader.vuejs.org/en/configurations/extract-css.html 49 | return { 50 | css: generateLoaders(), 51 | postcss: generateLoaders(), 52 | less: generateLoaders('less'), 53 | sass: generateLoaders('sass', { indentedSyntax: true }), 54 | scss: generateLoaders('sass'), 55 | stylus: generateLoaders('stylus'), 56 | styl: generateLoaders('stylus') 57 | } 58 | } 59 | 60 | // Generate loaders for standalone style files (outside of .vue) 61 | exports.styleLoaders = function (options) { 62 | const output = [] 63 | const loaders = exports.cssLoaders(options) 64 | for (const extension in loaders) { 65 | const loader = loaders[extension] 66 | output.push({ 67 | test: new RegExp('\\.' + extension + '$'), 68 | use: loader 69 | }) 70 | } 71 | return output 72 | } 73 | -------------------------------------------------------------------------------- /web/src/pages/project/project_member_list.vue: -------------------------------------------------------------------------------- 1 | 50 | 65 | -------------------------------------------------------------------------------- /project_test/migrations/0002_auto_20171115_1151.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # Generated by Django 1.11.7 on 2017-11-15 03:51 3 | from __future__ import unicode_literals 4 | 5 | from django.conf import settings 6 | from django.db import migrations, models 7 | import django.db.models.deletion 8 | 9 | 10 | class Migration(migrations.Migration): 11 | 12 | initial = True 13 | 14 | dependencies = [ 15 | ('project', '0002_auto_20171115_1151'), 16 | ('project_test', '0001_initial'), 17 | migrations.swappable_dependency(settings.AUTH_USER_MODEL), 18 | ] 19 | 20 | operations = [ 21 | migrations.AddField( 22 | model_name='testcasehistory', 23 | name='user', 24 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='修改员'), 25 | ), 26 | migrations.AddField( 27 | model_name='testcase', 28 | name='project', 29 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='project.Project', verbose_name='项目名称'), 30 | ), 31 | migrations.AddField( 32 | model_name='testcase', 33 | name='task', 34 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='project.ProjectTask', verbose_name='项目任务'), 35 | ), 36 | migrations.AddField( 37 | model_name='testcase', 38 | name='test', 39 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='project_test.Test', verbose_name='测试'), 40 | ), 41 | migrations.AddField( 42 | model_name='testcase', 43 | name='type', 44 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='project_test.TestType', verbose_name='测试类型'), 45 | ), 46 | migrations.AddField( 47 | model_name='test', 48 | name='project', 49 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='project.Project', verbose_name='项目名称'), 50 | ), 51 | migrations.AddField( 52 | model_name='test', 53 | name='type', 54 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='project_test.TestType', verbose_name='测试类型'), 55 | ), 56 | ] 57 | -------------------------------------------------------------------------------- /web/src/pages/project/project_task_card.vue: -------------------------------------------------------------------------------- 1 | 24 | 52 | 58 | 59 | -------------------------------------------------------------------------------- /web/src/pages/system/group/group_detail_home.vue: -------------------------------------------------------------------------------- 1 | 10 | 69 | 70 | -------------------------------------------------------------------------------- /static/js/15.4a0f80754bf9336425cb.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///static/js/15.4a0f80754bf9336425cb.js","webpack:///./src/pages/common/middle_router_view.vue?a933","webpack:///./src/pages/common/middle_router_view.vue"],"names":["webpackJsonp","OEdk","module","exports","render","_vm","this","_h","$createElement","_self","_c","staticRenderFns","cBoM","__webpack_require__","Component"],"mappings":"AAAAA,cAAc,KAERC,KACA,SAAUC,EAAQC,GCHxBD,EAAAC,SAAgBC,OAAA,WAAmB,GAAAC,GAAAC,KAAaC,EAAAF,EAAAG,cAChD,QAD0EH,EAAAI,MAAAC,IAAAH,GAC1E,gBACCI,qBDSKC,KACA,SAAUV,EAAQC,EAASU,GEZjC,GAAAC,GAAAD,EAAA,QAEA,KAEAA,EAAA,QAEA,KAEA,KAEA,KAGAX,GAAAC,QAAAW,EAAAX","file":"static/js/15.4a0f80754bf9336425cb.js","sourcesContent":["webpackJsonp([15],{\n\n/***/ \"OEdk\":\n/***/ (function(module, exports) {\n\nmodule.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;\n return _c('router-view')\n},staticRenderFns: []}\n\n/***/ }),\n\n/***/ \"cBoM\":\n/***/ (function(module, exports, __webpack_require__) {\n\nvar Component = __webpack_require__(\"VU/8\")(\n /* script */\n null,\n /* template */\n __webpack_require__(\"OEdk\"),\n /* styles */\n null,\n /* scopeId */\n null,\n /* moduleIdentifier (server only) */\n null\n)\n\nmodule.exports = Component.exports\n\n\n/***/ })\n\n});\n\n\n// WEBPACK FOOTER //\n// static/js/15.4a0f80754bf9336425cb.js","module.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;\n return _c('router-view')\n},staticRenderFns: []}\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/vue-loader/lib/template-compiler?{\"id\":\"data-v-1e14a3c6\",\"hasScoped\":false,\"transformToRequire\":{\"video\":\"src\",\"source\":\"src\",\"img\":\"src\",\"image\":\"xlink:href\"}}!./~/vue-loader/lib/selector.js?type=template&index=0!./src/pages/common/middle_router_view.vue\n// module id = OEdk\n// module chunks = 15","var Component = require(\"!../../../node_modules/vue-loader/lib/component-normalizer\")(\n /* script */\n null,\n /* template */\n require(\"!!../../../node_modules/vue-loader/lib/template-compiler/index?{\\\"id\\\":\\\"data-v-1e14a3c6\\\",\\\"hasScoped\\\":false,\\\"transformToRequire\\\":{\\\"video\\\":\\\"src\\\",\\\"source\\\":\\\"src\\\",\\\"img\\\":\\\"src\\\",\\\"image\\\":\\\"xlink:href\\\"}}!../../../node_modules/vue-loader/lib/selector?type=template&index=0!./middle_router_view.vue\"),\n /* styles */\n null,\n /* scopeId */\n null,\n /* moduleIdentifier (server only) */\n null\n)\n\nmodule.exports = Component.exports\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/pages/common/middle_router_view.vue\n// module id = cBoM\n// module chunks = 15"],"sourceRoot":""} -------------------------------------------------------------------------------- /static/js/14.a6ab56ad507ed6cf2077.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///static/js/14.a6ab56ad507ed6cf2077.js","webpack:///./src/pages/project_ci/form.vue?53ae","webpack:///./src/pages/project_ci/form.vue"],"names":["webpackJsonp","C2W4","module","exports","render","_vm","this","_h","$createElement","_self","_c","_v","staticRenderFns","obhH","__webpack_require__","Component"],"mappings":"AAAAA,cAAc,KAERC,KACA,SAAUC,EAAQC,GCHxBD,EAAAC,SAAgBC,OAAA,WAAmB,GAAAC,GAAAC,KAAaC,EAAAF,EAAAG,cAChD,QAD0EH,EAAAI,MAAAC,IAAAH,GAC1E,KAAAF,EAAAM,GAAA,uBACCC,qBDSKC,KACA,SAAUX,EAAQC,EAASW,GEZjC,GAAAC,GAAAD,EAAA,QAEA,KAEAA,EAAA,QAEA,KAEA,KAEA,KAGAZ,GAAAC,QAAAY,EAAAZ","file":"static/js/14.a6ab56ad507ed6cf2077.js","sourcesContent":["webpackJsonp([14],{\n\n/***/ \"C2W4\":\n/***/ (function(module, exports) {\n\nmodule.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;\n return _c('p', [_vm._v(\" project ci info\")])\n},staticRenderFns: []}\n\n/***/ }),\n\n/***/ \"obhH\":\n/***/ (function(module, exports, __webpack_require__) {\n\nvar Component = __webpack_require__(\"VU/8\")(\n /* script */\n null,\n /* template */\n __webpack_require__(\"C2W4\"),\n /* styles */\n null,\n /* scopeId */\n null,\n /* moduleIdentifier (server only) */\n null\n)\n\nmodule.exports = Component.exports\n\n\n/***/ })\n\n});\n\n\n// WEBPACK FOOTER //\n// static/js/14.a6ab56ad507ed6cf2077.js","module.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;\n return _c('p', [_vm._v(\" project ci info\")])\n},staticRenderFns: []}\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/vue-loader/lib/template-compiler?{\"id\":\"data-v-c6602a50\",\"hasScoped\":false,\"transformToRequire\":{\"video\":\"src\",\"source\":\"src\",\"img\":\"src\",\"image\":\"xlink:href\"}}!./~/vue-loader/lib/selector.js?type=template&index=0!./src/pages/project_ci/form.vue\n// module id = C2W4\n// module chunks = 14","var Component = require(\"!../../../node_modules/vue-loader/lib/component-normalizer\")(\n /* script */\n null,\n /* template */\n require(\"!!../../../node_modules/vue-loader/lib/template-compiler/index?{\\\"id\\\":\\\"data-v-c6602a50\\\",\\\"hasScoped\\\":false,\\\"transformToRequire\\\":{\\\"video\\\":\\\"src\\\",\\\"source\\\":\\\"src\\\",\\\"img\\\":\\\"src\\\",\\\"image\\\":\\\"xlink:href\\\"}}!../../../node_modules/vue-loader/lib/selector?type=template&index=0!./form.vue\"),\n /* styles */\n null,\n /* scopeId */\n null,\n /* moduleIdentifier (server only) */\n null\n)\n\nmodule.exports = Component.exports\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/pages/project_ci/form.vue\n// module id = obhH\n// module chunks = 14"],"sourceRoot":""} -------------------------------------------------------------------------------- /static/js/13.3a548fc888b607f48c6a.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack:///static/js/13.3a548fc888b607f48c6a.js","webpack:///./src/pages/project_ci/project_ci_home.vue","webpack:///./src/pages/project_ci/project_ci_home.vue?50dd"],"names":["webpackJsonp","0Qf1","module","exports","__webpack_require__","Component","SIth","render","_vm","this","_h","$createElement","_self","_c","_v","staticRenderFns"],"mappings":"AAAAA,cAAc,KAERC,OACA,SAAUC,EAAQC,EAASC,GCHjC,GAAAC,GAAAD,EAAA,QAEA,KAEAA,EAAA,QAEA,KAEA,KAEA,KAGAF,GAAAC,QAAAE,EAAAF,SDUMG,KACA,SAAUJ,EAAQC,GExBxBD,EAAAC,SAAgBI,OAAA,WAAmB,GAAAC,GAAAC,KAAaC,EAAAF,EAAAG,cAChD,QAD0EH,EAAAI,MAAAC,IAAAH,GAC1E,KAAAF,EAAAM,GAAA,yBACCC","file":"static/js/13.3a548fc888b607f48c6a.js","sourcesContent":["webpackJsonp([13],{\n\n/***/ \"0Qf1\":\n/***/ (function(module, exports, __webpack_require__) {\n\nvar Component = __webpack_require__(\"VU/8\")(\n /* script */\n null,\n /* template */\n __webpack_require__(\"SIth\"),\n /* styles */\n null,\n /* scopeId */\n null,\n /* moduleIdentifier (server only) */\n null\n)\n\nmodule.exports = Component.exports\n\n\n/***/ }),\n\n/***/ \"SIth\":\n/***/ (function(module, exports) {\n\nmodule.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;\n return _c('p', [_vm._v(\"project ci kanban \")])\n},staticRenderFns: []}\n\n/***/ })\n\n});\n\n\n// WEBPACK FOOTER //\n// static/js/13.3a548fc888b607f48c6a.js","var Component = require(\"!../../../node_modules/vue-loader/lib/component-normalizer\")(\n /* script */\n null,\n /* template */\n require(\"!!../../../node_modules/vue-loader/lib/template-compiler/index?{\\\"id\\\":\\\"data-v-5772708e\\\",\\\"hasScoped\\\":false,\\\"transformToRequire\\\":{\\\"video\\\":\\\"src\\\",\\\"source\\\":\\\"src\\\",\\\"img\\\":\\\"src\\\",\\\"image\\\":\\\"xlink:href\\\"}}!../../../node_modules/vue-loader/lib/selector?type=template&index=0!./project_ci_home.vue\"),\n /* styles */\n null,\n /* scopeId */\n null,\n /* moduleIdentifier (server only) */\n null\n)\n\nmodule.exports = Component.exports\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./src/pages/project_ci/project_ci_home.vue\n// module id = 0Qf1\n// module chunks = 13","module.exports={render:function (){var _vm=this;var _h=_vm.$createElement;var _c=_vm._self._c||_h;\n return _c('p', [_vm._v(\"project ci kanban \")])\n},staticRenderFns: []}\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./~/vue-loader/lib/template-compiler?{\"id\":\"data-v-5772708e\",\"hasScoped\":false,\"transformToRequire\":{\"video\":\"src\",\"source\":\"src\",\"img\":\"src\",\"image\":\"xlink:href\"}}!./~/vue-loader/lib/selector.js?type=template&index=0!./src/pages/project_ci/project_ci_home.vue\n// module id = SIth\n// module chunks = 13"],"sourceRoot":""} -------------------------------------------------------------------------------- /web/src/pages/project_bug/project_bug_list.vue: -------------------------------------------------------------------------------- 1 | 73 | 89 | -------------------------------------------------------------------------------- /web/src/pages/project_test/project_test_list.vue: -------------------------------------------------------------------------------- 1 | 74 | 90 | -------------------------------------------------------------------------------- /web/src/pages/base/aside.vue: -------------------------------------------------------------------------------- 1 | 35 | 71 | -------------------------------------------------------------------------------- /web/src/pages/project/project_home.vue: -------------------------------------------------------------------------------- 1 | 16 | 81 | -------------------------------------------------------------------------------- /web/src/pages/system/permission/permission_home.vue: -------------------------------------------------------------------------------- 1 | 15 | 83 | -------------------------------------------------------------------------------- /tcis_base/views/user.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # encoding: utf-8 3 | """ 4 | @project:tcis 5 | @author:cloudy 6 | @site: 7 | @file:login.py 8 | @date:2017/11/11 14:52 9 | """ 10 | 11 | from rest_framework import status, permissions 12 | from rest_framework import viewsets 13 | from rest_framework.decorators import list_route 14 | from rest_framework.response import Response 15 | from django.contrib.auth import login, logout 16 | from django.contrib.auth.forms import AuthenticationForm 17 | from ..serializers import UserSerializer 18 | from ..models import User 19 | 20 | 21 | class UserViewSet(viewsets.ModelViewSet): 22 | """ 23 | 用户 24 | """ 25 | queryset = User.objects.all() 26 | serializer_class = UserSerializer 27 | 28 | @list_route(["post"], permission_classes=[permissions.AllowAny]) 29 | def login(self, request): 30 | """ 31 | 用户登录 32 | :param request: 33 | :return: 34 | """ 35 | 36 | if not request.user.is_authenticated: 37 | form = AuthenticationForm(request, request.data) 38 | if form.is_valid(): 39 | user = form.user_cache 40 | login(request, user) 41 | return Response(UserSerializer(instance=user).data) 42 | return Response(u"用户名或密码错误", 43 | status=status.HTTP_403_FORBIDDEN) 44 | return Response(UserSerializer(instance=request.user).data) 45 | 46 | @list_route(["get"], permission_classes=[permissions.AllowAny]) 47 | def logout(self, request): 48 | """ 49 | 用户登出 50 | :param request: 51 | :return: 52 | """ 53 | logout(request) 54 | 55 | return Response(u"退出成功", status.HTTP_200_OK) 56 | 57 | @list_route(["post"], permission_classes=[permissions.IsAdminUser]) 58 | def reset_password(self, request): 59 | """ 60 | 用户登出 61 | :param request: 62 | :return: 63 | """ 64 | 65 | post_data = request.data 66 | password = post_data.get("password", None) 67 | confirm_password = post_data.get("confirm_password", None) 68 | user_id = post_data.get("user_id", None) 69 | if password != confirm_password: 70 | return Response(u"密码不一致", status.HTTP_400_BAD_REQUEST) 71 | try: 72 | user = User.objects.get(id=user_id) 73 | user.set_password(password) 74 | user.save() 75 | except Exception: 76 | return Response(u"用户不存在", status.HTTP_400_BAD_REQUEST) 77 | return Response(u"修改成功", status.HTTP_200_OK) 78 | 79 | @list_route(['post'], permission_classes=[permissions.IsAdminUser]) 80 | def user_active(self, request): 81 | """ 82 | 用户是否有效操作 83 | :param request: 84 | :return: 85 | """ 86 | user_ids = request.data.get("user_ids", []) 87 | try: 88 | is_active = request.data.is_active 89 | User.objects.filter(id__in=user_ids).update(is_active=is_active) 90 | return Response(u"修改成功", status.HTTP_200_OK) 91 | except Exception: 92 | return Response(u"缺少必须数据", status.HTTP_400_BAD_REQUEST) 93 | 94 | -------------------------------------------------------------------------------- /web/src/pages/system/group/group_form.vue: -------------------------------------------------------------------------------- 1 | 26 | 88 | 89 | -------------------------------------------------------------------------------- /web/src/pages/system/user/user_home.vue: -------------------------------------------------------------------------------- 1 | 17 | 95 | -------------------------------------------------------------------------------- /web/build/dev-server.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | require('./check-versions')() 3 | 4 | const config = require('../config') 5 | if (!process.env.NODE_ENV) { 6 | process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV) 7 | } 8 | 9 | const opn = require('opn') 10 | const path = require('path') 11 | const express = require('express') 12 | const webpack = require('webpack') 13 | const proxyMiddleware = require('http-proxy-middleware') 14 | const webpackConfig = require('./webpack.dev.conf') 15 | 16 | // default port where dev server listens for incoming traffic 17 | const port = process.env.PORT || config.dev.port 18 | // automatically open browser, if not set will be false 19 | const autoOpenBrowser = !!config.dev.autoOpenBrowser 20 | // Define HTTP proxies to your custom API backend 21 | // https://github.com/chimurai/http-proxy-middleware 22 | const proxyTable = config.dev.proxyTable 23 | 24 | const app = express() 25 | const compiler = webpack(webpackConfig) 26 | 27 | const devMiddleware = require('webpack-dev-middleware')(compiler, { 28 | publicPath: webpackConfig.output.publicPath, 29 | quiet: true 30 | }) 31 | 32 | const hotMiddleware = require('webpack-hot-middleware')(compiler, { 33 | log: false, 34 | heartbeat: 2000 35 | }) 36 | // force page reload when html-webpack-plugin template changes 37 | // currently disabled until this is resolved: 38 | // https://github.com/jantimon/html-webpack-plugin/issues/680 39 | // compiler.plugin('compilation', function (compilation) { 40 | // compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 41 | // hotMiddleware.publish({ action: 'reload' }) 42 | // cb() 43 | // }) 44 | // }) 45 | 46 | // enable hot-reload and state-preserving 47 | // compilation error display 48 | app.use(hotMiddleware) 49 | 50 | // proxy api requests 51 | Object.keys(proxyTable).forEach(function (context) { 52 | let options = proxyTable[context] 53 | if (typeof options === 'string') { 54 | options = { target: options } 55 | } 56 | app.use(proxyMiddleware(options.filter || context, options)) 57 | }) 58 | 59 | // handle fallback for HTML5 history API 60 | app.use(require('connect-history-api-fallback')()) 61 | 62 | // serve webpack bundle output 63 | app.use(devMiddleware) 64 | 65 | // serve pure static assets 66 | const staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) 67 | app.use(staticPath, express.static('./static')) 68 | 69 | const uri = 'http://localhost:' + port 70 | 71 | var _resolve 72 | var _reject 73 | var readyPromise = new Promise((resolve, reject) => { 74 | _resolve = resolve 75 | _reject = reject 76 | }) 77 | 78 | var server 79 | var portfinder = require('portfinder') 80 | portfinder.basePort = port 81 | 82 | console.log('> Starting dev server...') 83 | devMiddleware.waitUntilValid(() => { 84 | portfinder.getPort((err, port) => { 85 | if (err) { 86 | _reject(err) 87 | } 88 | process.env.PORT = port 89 | var uri = 'http://localhost:' + port 90 | console.log('> Listening at ' + uri + '\n') 91 | // when env is testing, don't need open it 92 | if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') { 93 | opn(uri) 94 | } 95 | server = app.listen(port) 96 | _resolve() 97 | }) 98 | }) 99 | 100 | module.exports = { 101 | ready: readyPromise, 102 | close: () => { 103 | server.close() 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /web/src/router.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | 4 | Vue.use(VueRouter) 5 | const Login = resolve => require(['@/pages/base/login'], resolve); 6 | const Home = resolve => require(['@/pages/base/home'], resolve); 7 | const Page404 = resolve => require(['@/pages/common/page_404'], resolve); 8 | 9 | const MiddleRouterView = resolve => require(['@/pages/common/middle_router_view'], resolve); 10 | // 权限组 11 | const GroupHome = resolve => require(['@/pages/system/group/group_home'], resolve); 12 | const GroupInfo = resolve => require(['@/pages/system/group/group_detail_home'], resolve); 13 | 14 | // 权限明细 15 | const PermissionForm = resolve => require(['@/pages/system/permission/permission_home'], resolve); 16 | // 用户 17 | const UserHome = resolve => require(['@/pages/system/user/user_home'], resolve); 18 | const UserInfo = resolve => require(['@/pages/system/user/user_detail_home'], resolve); 19 | // 项目管理 20 | const ProjectHome = resolve => require(['@/pages/project/project_home'], resolve); 21 | const ProjectInfo = resolve => require(['@/pages/project/project_detail_home'], resolve); 22 | // 项目任务管理 23 | const ProjectTaskHome = resolve => require(['@/pages/project/project_task_home'], resolve); 24 | const ProjectTaskInfo = resolve => require(['@/pages/project/project_task_detail_home'], resolve); 25 | 26 | // 项目bug 27 | const ProjectBugHome = resolve => require(['@/pages/project_bug/project_bug_home'], resolve); 28 | const ProjectBugInfo = resolve => require(['@/pages/project_bug/project_bug_detail_home'], resolve); 29 | 30 | // 项目集成 31 | const ProjectCIHome = resolve => require(['@/pages/project_ci/project_ci_home'], resolve); 32 | const ProjectCIInfo = resolve => require(['@/pages/project_ci/form'], resolve); 33 | 34 | // 项目测试 35 | const ProjectTestHome = resolve => require(['@/pages/project_test/project_test_home'], resolve); 36 | const ProjectTestInfo = resolve => require(['@/pages/project_test/project_test_detail_home'], resolve); 37 | 38 | let routes = [{ 39 | path: "/", 40 | name: "home", 41 | component: Home, 42 | children: [ 43 | // 用户组 44 | { path: "/group/:id", component: GroupInfo, }, 45 | { path: "/group/", component: GroupHome, }, 46 | 47 | // 用户 48 | { path: "/user/:id", component: UserInfo, }, 49 | { path: "/user/", component: UserHome, }, 50 | 51 | // 权限 52 | { path: "/permission/", component: PermissionForm, }, 53 | // 项目管理 54 | { path: "/project/:id", component: ProjectInfo, }, 55 | { path: "/project/", component: ProjectHome, }, 56 | { path: "/project_task/:id", component: ProjectTaskInfo, }, 57 | { path: "/project_task/", component: ProjectTaskHome, }, 58 | // 项目集成 59 | { path: "/project_ci/:id", component: ProjectCIInfo, }, 60 | // Bug管理 61 | { path: "/project_bug/:id", component: ProjectBugInfo, }, 62 | { path: "/project_bug/", component: ProjectBugHome, }, 63 | // 测试管理 64 | { path: "/project_test/:id", component: ProjectTestInfo, }, 65 | { path: "/project_test/", component: ProjectTestHome, }, 66 | 67 | ] 68 | }, 69 | { path: "/login", name: 'login', component: Login }, 70 | // error 71 | { path: "/*", name: 'error', component: Page404 }, 72 | 73 | ]; 74 | 75 | export default new VueRouter({ 76 | // mode: 'history', 77 | base: __dirname, 78 | routes: routes 79 | }); -------------------------------------------------------------------------------- /web/src/pages/project_test/project_test_card_echart.vue: -------------------------------------------------------------------------------- 1 | 5 | 92 | --------------------------------------------------------------------------------