├── .idea
├── .name
├── inspectionProfiles
│ ├── Project_Default.xml
│ └── profiles_settings.xml
├── misc.xml
├── modules.xml
├── vfOA.iml
└── workspace.xml
├── README.md
├── db111.sqlite3
├── demo
├── README.rst
├── __init__.py
├── bloodtest
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── flows.py
│ ├── forms.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── templates
│ │ └── bloodtest
│ │ │ └── bloodtest
│ │ │ ├── biochemical_data.html
│ │ │ ├── first_sample.html
│ │ │ ├── hormone_data.html
│ │ │ └── second_sample.html
│ └── views.py
├── countersign
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── flows.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_auto_20171127_1554.py
│ │ └── __init__.py
│ ├── models.py
│ └── tests.py
├── customnode
│ ├── README.rst
│ ├── __init__.py
│ ├── doc
│ │ └── DynamicSplit.png
│ ├── flows.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── nodes.py
│ ├── urls.py
│ └── views.py
├── employees
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── forms.py
│ ├── locale
│ │ ├── de
│ │ │ └── LC_MESSAGES
│ │ │ │ ├── django.mo
│ │ │ │ └── django.po
│ │ ├── es
│ │ │ └── LC_MESSAGES
│ │ │ │ ├── django.mo
│ │ │ │ └── django.po
│ │ ├── fr
│ │ │ └── LC_MESSAGES
│ │ │ │ ├── django.mo
│ │ │ │ └── django.po
│ │ ├── ko
│ │ │ └── LC_MESSAGES
│ │ │ │ ├── django.mo
│ │ │ │ └── django.po
│ │ ├── ru
│ │ │ └── LC_MESSAGES
│ │ │ │ ├── django.mo
│ │ │ │ └── django.po
│ │ └── zh_Hans
│ │ │ └── LC_MESSAGES
│ │ │ ├── django.mo
│ │ │ └── django.po
│ ├── managers.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_i18n.py
│ │ └── __init__.py
│ ├── models.py
│ ├── templates
│ │ └── employees
│ │ │ ├── base_module.html
│ │ │ ├── change_manager.html
│ │ │ ├── change_salary.html
│ │ │ ├── change_title.html
│ │ │ ├── department_detail.html
│ │ │ ├── department_employees.html
│ │ │ ├── employee_detail.html
│ │ │ └── menu.html
│ ├── urls.py
│ └── views.py
├── hr
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── integration
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── locale
│ │ ├── de
│ │ │ └── LC_MESSAGES
│ │ │ │ ├── django.mo
│ │ │ │ └── django.po
│ │ ├── es
│ │ │ └── LC_MESSAGES
│ │ │ │ ├── django.mo
│ │ │ │ └── django.po
│ │ ├── fr
│ │ │ └── LC_MESSAGES
│ │ │ │ ├── django.mo
│ │ │ │ └── django.po
│ │ ├── ko
│ │ │ └── LC_MESSAGES
│ │ │ │ ├── django.mo
│ │ │ │ └── django.po
│ │ ├── ru
│ │ │ └── LC_MESSAGES
│ │ │ │ ├── django.mo
│ │ │ │ └── django.po
│ │ └── zh_Hans
│ │ │ └── LC_MESSAGES
│ │ │ ├── django.mo
│ │ │ └── django.po
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_i18n.py
│ │ ├── 0003_auto_20171128_1814.py
│ │ └── __init__.py
│ ├── models.py
│ ├── templates
│ │ └── integration
│ │ │ ├── base_module.html
│ │ │ └── menu.html
│ ├── urls.py
│ └── views.py
├── leave
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── flows.py
│ ├── forms.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ ├── 0002_leave_comment.py
│ │ ├── 0003_auto_20171130_0922.py
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
├── settings.py
├── static
│ ├── demo
│ │ ├── css
│ │ │ ├── shepherd-theme-arrows.css
│ │ │ └── vfOA.css
│ │ └── js
│ │ │ ├── jquery.cookie.js
│ │ │ └── shepherd.js
│ └── material
│ │ ├── css
│ │ ├── materialize.admin.css
│ │ ├── materialize.admin.min.css
│ │ ├── materialize.css
│ │ ├── materialize.forms.css
│ │ ├── materialize.frontend.css
│ │ └── materialize.frontend.min.css
│ │ └── imgs
│ │ ├── background.svg
│ │ └── sidenav.svg
├── templates
│ ├── admin
│ │ └── testing
│ │ │ └── Contract
│ │ │ └── change_list.html
│ ├── demo
│ │ ├── base_module.html
│ │ ├── index.html
│ │ └── wizard.html
│ ├── hr
│ │ └── menu.html
│ ├── leave
│ │ ├── check.html
│ │ ├── menu.html
│ │ └── start.html
│ └── material
│ │ ├── fields
│ │ ├── _django_rangeinput.html
│ │ ├── django_checkboxinput.html
│ │ ├── django_checkboxselectmultiple.html
│ │ ├── django_clearablefileinput.html
│ │ ├── django_dateinput.html
│ │ ├── django_datetimeinput.html
│ │ ├── django_fileinput.html
│ │ ├── django_input.html
│ │ ├── django_nullbooleanselect.html
│ │ ├── django_radioselect.html
│ │ ├── django_select.html
│ │ ├── django_selectdatewidget.html
│ │ ├── django_selectmultiple.html
│ │ ├── django_splitdatetimewidget.html
│ │ ├── django_textarea.html
│ │ └── django_timeinput.html
│ │ └── frontend
│ │ └── base_site.html
├── testing
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── forms.py
│ ├── migrations
│ │ ├── 0001_initial.py
│ │ └── __init__.py
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── urls.py
└── website.py
├── img
├── 1.PNG
├── 2.PNG
├── 3.PNG
├── 4.PNG
└── 5.PNG
├── manage.py
└── requirements.txt
/.idea/.name:
--------------------------------------------------------------------------------
1 | vfOA
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/Project_Default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/.idea/inspectionProfiles/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | AngularJS
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vfOA.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | vfOA
2 | ==========
3 |
4 | vfOA是基于Viewflow的OA演示系统,能够快速实现数据的CURD以及流程处理,可开发轻量级OA/CRM/ERP等系统。
5 |
6 | 更多内容请参考django-viewflow、django-materia
7 | ## Installation and Dependencies:
8 |
9 | django==1.11.7
10 |
11 | django-filter==1.1.0
12 |
13 | django-formtools==2.1
14 |
15 | django-material==1.1.1
16 |
17 | django-viewflow==1.1.0
18 |
19 | ## Quick start:
20 | pip install -r requirements.txt
21 |
22 | python manage.py runserver 8888
23 |
24 | ## Photos:
25 | 编辑界面
26 | 
27 |
28 | 列表页面
29 | 
30 |
31 | 代办事项
32 | 
33 |
34 | 流程处理
35 | 
36 |
37 | 流程信息展示
38 | 
39 |
--------------------------------------------------------------------------------
/db111.sqlite3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/db111.sqlite3
--------------------------------------------------------------------------------
/demo/README.rst:
--------------------------------------------------------------------------------
1 | =============
2 | Viewflow Demo
3 | =============
4 |
5 | See live at: http://demo.viewflow.io or checkout and run:
6 |
7 | .. code-block:: shell
8 |
9 | tox migrate
10 | tox loaddata tests/helloworld/fixtures/default_data.json
11 | tox loaddata tests/shipment/fixtures/default_data.json
12 | tox runserver
13 |
14 | And get access on http://127.0.0.1:8000
15 |
16 |
17 | * HelloWorld_ - Viewflow introduction sample
18 | * Shipment_ - Automate shipment process for ecommerce website
19 | * `Dynamic split`_ - Custom flow node example
20 |
21 | .. _HelloWorld: helloworld/
22 | .. _Shipment: shipment/
23 | .. _`Dynamic split`: customnode/
24 |
25 |
26 | Standalone demo projects
27 | ========================
28 |
29 | * Ecommerce_ - Delivery department automation with viewflow and Django Cartridge Ecommerce
30 | * Customization_ - Custom auth model and django-guardian for object level permissions, no viewsite
31 |
32 | .. _Ecommerce: https://github.com/kmmbvnr/viewflow-demo/tree/master/ecommerce
33 | .. _Customization: https://github.com/kmmbvnr/viewflow-demo/tree/master/customauth
34 |
--------------------------------------------------------------------------------
/demo/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/__init__.py
--------------------------------------------------------------------------------
/demo/bloodtest/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/bloodtest/__init__.py
--------------------------------------------------------------------------------
/demo/bloodtest/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from .models import *
3 | # Register your models here.
4 | @admin.register(Patient)
5 | class PatientAdmin(admin.ModelAdmin):
6 | pass
7 |
8 | @admin.register(BloodTestProcess)
9 | class BloodTestProcessAdmin(admin.ModelAdmin):
10 | pass
--------------------------------------------------------------------------------
/demo/bloodtest/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class BloodtestConfig(AppConfig):
5 | name = 'bloodtest'
6 |
--------------------------------------------------------------------------------
/demo/bloodtest/flows.py:
--------------------------------------------------------------------------------
1 | from viewflow import flow, frontend
2 | from viewflow.base import this, Flow
3 |
4 | from . import views, models
5 |
6 |
7 | @frontend.register
8 | class BloodTestFlow(Flow):
9 | process_class = models.BloodTestProcess
10 |
11 | first_sample = flow.Start(
12 | views.FirstBoodSampleView
13 | ).Next(this.biochemical_analysis)
14 |
15 | second_sample = flow.Start(
16 | views.second_blood_sample
17 | ).Next(this.biochemical_analysis)
18 |
19 | biochemical_analysis = flow.View(
20 | views.biochemical_data
21 | ).Next(this.split_analysis)
22 |
23 | split_analysis = (
24 | flow.Split()
25 | .Next(
26 | this.hormone_tests,
27 | cond=lambda act: act.process.hormone_test_required
28 | ).Next(
29 | this.tumor_markers_test,
30 | cond=lambda act: act.process.tumor_test_required
31 | ).Next(
32 | this.join_analysis
33 | )
34 | )
35 |
36 | hormone_tests = flow.View(
37 | views.HormoneTestFormView
38 | ).Next(this.join_analysis)
39 |
40 | tumor_markers_test = flow.View(
41 | views.GenericTestFormView,
42 | model=models.TumorMarkers,
43 | fields=[
44 | 'alpha_fetoprotein', 'beta_gonadotropin', 'ca19',
45 | 'cea', 'pap', 'pas'
46 | ],
47 | task_description='Tumor Markers Test'
48 | ).Next(this.join_analysis)
49 |
50 | join_analysis = flow.Join().Next(this.end)
51 |
52 | end = flow.End()
53 |
--------------------------------------------------------------------------------
/demo/bloodtest/forms.py:
--------------------------------------------------------------------------------
1 | from django import forms
2 | from material import Layout, Row, Span2
3 |
4 | from . import models
5 |
6 |
7 | class PatientForm(forms.ModelForm):
8 | layout = Layout(
9 | Row(Span2('patient_id'), 'age', 'sex'),
10 | Row('weight', 'height'),
11 | 'comment',
12 | )
13 |
14 | class Meta:
15 | model = models.Patient
16 | fields = '__all__'
17 |
18 |
19 | class BloodSampleForm(forms.ModelForm):
20 | class Meta:
21 | model = models.BloodSample
22 | fields = ['taken_at', 'notes']
23 |
24 |
25 | class BiochemistryForm(forms.ModelForm):
26 | class Meta:
27 | model = models.Biochemistry
28 | fields = ['hemoglobin', 'lymphocytes']
29 |
30 |
31 | class SecondBloodSampleForm(BloodSampleForm):
32 | patient = forms.ModelChoiceField(queryset=models.Patient.objects.all())
33 |
--------------------------------------------------------------------------------
/demo/bloodtest/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.11.7 on 2017-11-22 08:56
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 | import django.utils.timezone
9 |
10 |
11 | class Migration(migrations.Migration):
12 |
13 | initial = True
14 |
15 | dependencies = [
16 | migrations.swappable_dependency(settings.AUTH_USER_MODEL),
17 | ('viewflow', '0006_i18n'),
18 | ]
19 |
20 | operations = [
21 | migrations.CreateModel(
22 | name='Biochemistry',
23 | fields=[
24 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
25 | ('hemoglobin', models.IntegerField(help_text='g/dL')),
26 | ('lymphocytes', models.DecimalField(decimal_places=1, help_text='10^9/L', max_digits=3)),
27 | ],
28 | ),
29 | migrations.CreateModel(
30 | name='BloodSample',
31 | fields=[
32 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
33 | ('taken_at', models.DateTimeField(default=django.utils.timezone.now)),
34 | ('notes', models.TextField(blank=True)),
35 | ],
36 | ),
37 | migrations.CreateModel(
38 | name='BloodTestProcess',
39 | fields=[
40 | ('process_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='viewflow.Process')),
41 | ('sample', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='bloodtest.BloodSample')),
42 | ],
43 | options={
44 | 'abstract': False,
45 | },
46 | bases=('viewflow.process',),
47 | ),
48 | migrations.CreateModel(
49 | name='Hormones',
50 | fields=[
51 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
52 | ('acth', models.DecimalField(decimal_places=1, help_text='pmol/L', max_digits=3)),
53 | ('estradiol', models.IntegerField(help_text='ng/dL')),
54 | ('free_t3', models.DecimalField(decimal_places=1, help_text='ng/dL', max_digits=3)),
55 | ('free_t4', models.IntegerField(help_text='pmol/L')),
56 | ('sample', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='bloodtest.BloodSample')),
57 | ],
58 | ),
59 | migrations.CreateModel(
60 | name='Patient',
61 | fields=[
62 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
63 | ('patient_id', models.CharField(max_length=250)),
64 | ('age', models.IntegerField()),
65 | ('sex', models.CharField(choices=[('M', 'Male'), ('F', 'Female'), ('O', 'Other'), ('U', 'Unknown')], max_length=1)),
66 | ('weight', models.DecimalField(decimal_places=1, help_text='kg', max_digits=4)),
67 | ('height', models.IntegerField(help_text='cm')),
68 | ('comment', models.TextField(blank=True)),
69 | ],
70 | ),
71 | migrations.CreateModel(
72 | name='TumorMarkers',
73 | fields=[
74 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
75 | ('alpha_fetoprotein', models.IntegerField(help_text='ng/mL')),
76 | ('beta_gonadotropin', models.IntegerField(help_text='IU/I')),
77 | ('ca19', models.IntegerField(help_text='U/mL')),
78 | ('cea', models.IntegerField(help_text='ug/L')),
79 | ('pap', models.IntegerField(help_text='U/dL')),
80 | ('pas', models.IntegerField(help_text='ug/L')),
81 | ('sample', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='bloodtest.BloodSample')),
82 | ],
83 | ),
84 | migrations.AddField(
85 | model_name='bloodsample',
86 | name='patient',
87 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='bloodtest.Patient'),
88 | ),
89 | migrations.AddField(
90 | model_name='bloodsample',
91 | name='taken_by',
92 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
93 | ),
94 | migrations.AddField(
95 | model_name='biochemistry',
96 | name='sample',
97 | field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to='bloodtest.BloodSample'),
98 | ),
99 | ]
100 |
--------------------------------------------------------------------------------
/demo/bloodtest/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/bloodtest/migrations/__init__.py
--------------------------------------------------------------------------------
/demo/bloodtest/models.py:
--------------------------------------------------------------------------------
1 | from django.contrib.auth.models import User
2 | from django.db import models
3 | from django.utils import timezone
4 | from viewflow.models import Process
5 |
6 |
7 | class Patient(models.Model):
8 | patient_id = models.CharField(max_length=250)
9 | age = models.IntegerField()
10 | sex = models.CharField(
11 | max_length=1,
12 | choices=(
13 | ("M", "Male"),
14 | ("F", "Female"),
15 | ("O", "Other"),
16 | ("U", "Unknown")))
17 | weight = models.DecimalField(
18 | max_digits=4, decimal_places=1,
19 | help_text='kg')
20 | height = models.IntegerField(help_text="cm")
21 | comment = models.TextField(blank=True)
22 |
23 | def __str__(self):
24 | return self.patient_id
25 |
26 |
27 | class BloodSample(models.Model):
28 | patient = models.ForeignKey(Patient)
29 | taken_at = models.DateTimeField(default=timezone.now)
30 | taken_by = models.ForeignKey(User)
31 | notes = models.TextField(blank=True)
32 |
33 |
34 | class Biochemistry(models.Model):
35 | sample = models.OneToOneField(BloodSample)
36 | hemoglobin = models.IntegerField(help_text='g/dL')
37 | lymphocytes = models.DecimalField(max_digits=3, decimal_places=1, help_text='10^9/L')
38 |
39 |
40 | class TumorMarkers(models.Model):
41 | sample = models.OneToOneField(BloodSample)
42 | alpha_fetoprotein = models.IntegerField(help_text='ng/mL')
43 | beta_gonadotropin = models.IntegerField(help_text='IU/I')
44 | ca19 = models.IntegerField(help_text='U/mL')
45 | cea = models.IntegerField(help_text='ug/L')
46 | pap = models.IntegerField(help_text='U/dL')
47 | pas = models.IntegerField(help_text='ug/L')
48 |
49 |
50 | class Hormones(models.Model):
51 | sample = models.OneToOneField(BloodSample)
52 | acth = models.DecimalField(max_digits=3, decimal_places=1, help_text='pmol/L')
53 | estradiol = models.IntegerField(help_text='ng/dL')
54 | free_t3 = models.DecimalField(max_digits=3, decimal_places=1, help_text='ng/dL')
55 | free_t4 = models.IntegerField(help_text='pmol/L')
56 |
57 |
58 | class BloodTestProcess(Process):
59 | sample = models.ForeignKey(BloodSample)
60 |
61 | @property
62 | def tumor_test_required(self):
63 | return self.sample.biochemistry.lymphocytes > 5
64 |
65 | @property
66 | def hormone_test_required(self):
67 | return self.sample.biochemistry.hemoglobin < 12
68 |
--------------------------------------------------------------------------------
/demo/bloodtest/templates/bloodtest/bloodtest/biochemical_data.html:
--------------------------------------------------------------------------------
1 | {% extends 'viewflow/flow/task.html' %}
2 |
--------------------------------------------------------------------------------
/demo/bloodtest/templates/bloodtest/bloodtest/first_sample.html:
--------------------------------------------------------------------------------
1 | {% extends 'viewflow/flow/start.html' %}
2 | {% load viewflow material_form material_frontend %}
3 |
4 | {% block left-panel %}
5 |
33 | {% endblock %}
34 |
--------------------------------------------------------------------------------
/demo/bloodtest/templates/bloodtest/bloodtest/hormone_data.html:
--------------------------------------------------------------------------------
1 | {% extends 'viewflow/flow/task.html' %}
2 |
--------------------------------------------------------------------------------
/demo/bloodtest/templates/bloodtest/bloodtest/second_sample.html:
--------------------------------------------------------------------------------
1 | {% extends 'viewflow/flow/start.html' %}
2 |
--------------------------------------------------------------------------------
/demo/bloodtest/views.py:
--------------------------------------------------------------------------------
1 | from django.views import generic
2 | from django.shortcuts import render, redirect
3 | from formtools.wizard.views import SessionWizardView
4 |
5 | from viewflow.decorators import flow_start_view, flow_view
6 | from viewflow.flow.views import StartFlowMixin, FlowMixin
7 | from viewflow.flow.views.utils import get_next_task_url
8 |
9 | from . import forms, models
10 |
11 |
12 | class FirstBoodSampleView(StartFlowMixin, SessionWizardView):
13 | template_name = 'bloodtest/bloodtest/first_sample.html'
14 |
15 | form_list = [forms.PatientForm, forms.BloodSampleForm]
16 |
17 | def done(self, form_list, form_dict, **kwargs):
18 | patient = form_dict['0'].save()
19 |
20 | sample = form_dict['1'].save(commit=False)
21 | sample.patient = patient
22 | sample.taken_by = self.request.user
23 | sample.save()
24 |
25 | self.activation.process.sample = sample
26 | self.activation.done()
27 |
28 | return redirect(get_next_task_url(self.request, self.activation.process))
29 |
30 |
31 | @flow_start_view
32 | def second_blood_sample(request, **kwargs):
33 | request.activation.prepare(request.POST or None, user=request.user)
34 | form = forms.SecondBloodSampleForm(request.POST or None)
35 |
36 | if form.is_valid():
37 | sample = form.save(commit=False)
38 | sample.patient = form.cleaned_data['patient']
39 | sample.taken_by = request.user
40 | sample.save()
41 |
42 | request.activation.process.sample = sample
43 | request.activation.done()
44 |
45 | return redirect(get_next_task_url(request, request.activation.process))
46 |
47 | return render(request, 'bloodtest/bloodtest/second_sample.html', {
48 | 'form': form,
49 | 'activation': request.activation
50 | })
51 |
52 |
53 | @flow_view
54 | def biochemical_data(request, **kwargs):
55 | request.activation.prepare(request.POST or None, user=request.user)
56 | form = forms.BiochemistryForm(request.POST or None)
57 |
58 | if form.is_valid():
59 | biochemestry = form.save(commit=False)
60 | biochemestry.sample = request.activation.process.sample
61 | biochemestry.save()
62 | request.activation.done()
63 | return redirect(get_next_task_url(request, request.activation.process))
64 |
65 | return render(request, 'bloodtest/bloodtest/biochemical_data.html', {
66 | 'form': form,
67 | 'activation': request.activation
68 | })
69 |
70 |
71 | class HormoneTestFormView(FlowMixin, generic.CreateView):
72 | template_name = 'bloodtest/bloodtest/hormone_data.html'
73 | model = models.Hormones
74 | fields = [
75 | 'acth', 'estradiol', 'free_t3', 'free_t4'
76 | ]
77 |
78 | def form_valid(self, form):
79 | hormone_data = form.save(commit=False)
80 | hormone_data.sample = self.activation.process.sample
81 | hormone_data.save()
82 | self.activation_done()
83 | return redirect(self.get_success_url())
84 |
85 |
86 | class GenericTestFormView(FlowMixin, generic.CreateView):
87 | """A generic view to save blood test data.
88 |
89 | Assumes that test data model have FK `sample` field. The view can
90 | be parametrized directly in flow definition.
91 |
92 | """
93 | def form_valid(self, form):
94 | test_data = form.save(commit=False)
95 | test_data.sample = self.activation.process.sample
96 | test_data.save()
97 | self.activation_done()
98 | return redirect(self.get_success_url())
99 |
--------------------------------------------------------------------------------
/demo/countersign/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/countersign/__init__.py
--------------------------------------------------------------------------------
/demo/countersign/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from .models import *
3 | # Register your models here.
4 | @admin.register(cs_process)
5 | class CSAdmin(admin.ModelAdmin):
6 | list_display = ( 'version', 'mark')
--------------------------------------------------------------------------------
/demo/countersign/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class CountersignConfig(AppConfig):
5 | icon = 'flag '
6 | name = 'demo.countersign'
7 |
--------------------------------------------------------------------------------
/demo/countersign/flows.py:
--------------------------------------------------------------------------------
1 | import os
2 | from django.utils.translation import ugettext_lazy as _
3 |
4 | from viewflow import flow, frontend, lock
5 | from viewflow.base import this, Flow
6 | from viewflow.flow import views as flow_views
7 |
8 |
9 | from .models import cs_process
10 |
11 |
12 | @frontend.register
13 | class CSFlow(Flow):
14 | """
15 | 并行会签demo
16 | 动态拆分见作者自带的customnode列子。
17 | """
18 | process_class = cs_process
19 | process_title = _('会签')
20 | process_description = _('会签演示.')
21 |
22 | lock_impl = lock.select_for_update_lock
23 |
24 | summary_template = _("'{{ process.mark }}' 会签")
25 |
26 | start = (
27 | flow.Start(
28 | flow_views.CreateProcessView,
29 | fields=['file','mark','version'],
30 | task_title=_('新会签'))
31 | .Permission(auto_create=True)
32 | .Next(this.split_sign)
33 | )
34 |
35 | split_sign=(
36 | flow.Split(
37 | task_title=_('并行会签')
38 | )
39 | .Next(this.cfo_sign)
40 | .Next(this.ceo_sign)
41 | )
42 |
43 | #财务官会签
44 | cfo_sign=(
45 | flow.View(
46 | flow_views.UpdateProcessView, fields=['file','mark','cfo_approved'],
47 | task_title=_('CFO 会签'),
48 | task_result_summary = _("CFO{% ifequal process.cfo_approved '1' %} 同意 {% else %}不同意{% endifequal %}")
49 | )
50 | .Permission(auto_create=True)
51 | .Next(this.join_on_sign)
52 | )
53 |
54 | #CEO会签
55 | ceo_sign=(
56 | flow.View(
57 | flow_views.UpdateProcessView, fields=['file','mark','ceo_approved'],
58 | task_title=_('CEO 会签'),
59 | task_result_summary = _("CEO{% if process.ceo_approved == '1' %} 同意 {% else %}不同意{% endif %}")
60 | )
61 | .Permission(auto_create=True)
62 | .Next(this.join_on_sign)
63 | )
64 |
65 | join_on_sign = (
66 | flow.Join(
67 | task_title=_('等待所有会签结束')
68 | ).Next(this.decision)
69 | )
70 | #一票否决制。
71 | decision = (
72 | flow.If(
73 | cond=lambda act: act.process.cfo_approved=='1' and act.process.ceo_approved=='1',
74 | task_title=_('会签结果'),
75 | task_result_summary=_("会签结果{% if process.ceo_approved == '1' and process.cfo_approved == '1'%} 通过 {% else %}不通过{% endif %}")
76 | )
77 | .Then(this.OK)
78 | .Else(this.NG)
79 | )
80 |
81 | NG = (
82 | flow.Handler(
83 | this.send_NG_request
84 | ).Next(this.end)
85 | )
86 |
87 | OK = (
88 | flow.Handler(
89 | this.send_OK_request
90 | ).Next(this.end)
91 | )
92 |
93 | end = flow.End()
94 |
95 | def send_NG_request(self, activation):
96 | print('ceo_approved==>'+ str(activation.process.ceo_approved))
97 | print('cfo_approved==>' + str(activation.process.cfo_approved))
98 | print('NG')
99 |
100 | def send_OK_request(self, activation):
101 | print('OK')
--------------------------------------------------------------------------------
/demo/countersign/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.11.7 on 2017-11-27 06:17
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 | ('viewflow', '0006_i18n'),
15 | ]
16 |
17 | operations = [
18 | migrations.CreateModel(
19 | name='cs_process',
20 | fields=[
21 | ('process_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='viewflow.Process')),
22 | ('version', models.CharField(max_length=50, verbose_name='版本')),
23 | ('mark', models.CharField(max_length=1024, verbose_name='备注')),
24 | ('cfo_approved', models.CharField(choices=[('1', '同意'), ('2', '不同意')], max_length=1)),
25 | ('ceo_approved', models.CharField(choices=[('1', '同意'), ('2', '不同意')], max_length=1)),
26 | ],
27 | options={
28 | 'verbose_name': '会签',
29 | 'verbose_name_plural': '会签',
30 | },
31 | bases=('viewflow.process',),
32 | ),
33 | ]
34 |
--------------------------------------------------------------------------------
/demo/countersign/migrations/0002_auto_20171127_1554.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.11.7 on 2017-11-27 07:54
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('countersign', '0001_initial'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='cs_process',
17 | name='file',
18 | field=models.FileField(default='blank', upload_to='./upload/', verbose_name='会签文件'),
19 | preserve_default=False,
20 | ),
21 | migrations.AlterField(
22 | model_name='cs_process',
23 | name='ceo_approved',
24 | field=models.CharField(choices=[('1', '同意'), ('0', '不同意')], max_length=1),
25 | ),
26 | migrations.AlterField(
27 | model_name='cs_process',
28 | name='cfo_approved',
29 | field=models.CharField(choices=[('1', '同意'), ('0', '不同意')], max_length=1),
30 | ),
31 | ]
32 |
--------------------------------------------------------------------------------
/demo/countersign/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/countersign/migrations/__init__.py
--------------------------------------------------------------------------------
/demo/countersign/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from viewflow.models import Process
3 | from django.utils.translation import ugettext_lazy as _
4 | # Create your models here.
5 |
6 | class cs_process(Process):
7 | #能上传,但不支持下载,可以自定义FORM模板下载
8 | file=models.FileField(_('会签文件'), upload_to = './upload/')
9 | version = models.CharField(_('版本'), max_length=50)
10 | mark = models.CharField(_('备注'), max_length=1024)
11 |
12 | cfo_approved = models.CharField(
13 | max_length=1,
14 | choices=(
15 | ("1", "同意"),
16 | ("0", "不同意"),))
17 |
18 | ceo_approved = models.CharField(
19 | max_length=1,
20 | choices=(
21 | ("1", "同意"),
22 | ("0", "不同意"),))
23 |
24 | class Meta:
25 | verbose_name = _("会签")
26 | verbose_name_plural = _('会签')
--------------------------------------------------------------------------------
/demo/countersign/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/demo/customnode/README.rst:
--------------------------------------------------------------------------------
1 | ==================
2 | Extending Viewflow
3 | ==================
4 |
5 | http://demo.viewflow.io/workflow/dynamicsplit/
6 |
7 | In this process we are collecting responses (yes, no) from different users and Join that.
8 | Required users count determined in the first step.
9 |
10 | .. image:: doc/DynamicSplit.png
11 | :width: 400px
12 |
13 | `nodes.DynamicSplit`_ - Custom dynamic split node example
14 |
15 | .. _`nodes.DynamicSplit`: nodes.py
16 |
17 |
--------------------------------------------------------------------------------
/demo/customnode/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/customnode/__init__.py
--------------------------------------------------------------------------------
/demo/customnode/doc/DynamicSplit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/customnode/doc/DynamicSplit.png
--------------------------------------------------------------------------------
/demo/customnode/flows.py:
--------------------------------------------------------------------------------
1 | from viewflow import flow, frontend
2 | from viewflow.base import this, Flow
3 | from viewflow.flow.views import CreateProcessView
4 |
5 | from . import models, views
6 | from .nodes import DynamicSplit
7 |
8 |
9 | class DynamicSplitFlow(Flow):
10 | """
11 | Dynamic split
12 |
13 | Depends on initial decision, several instances on make_decision task would be instantiated
14 | """
15 | process_class = models.DynamicSplitProcess
16 |
17 | summary_template = """
18 | Decision on: {{ process.question }}
19 | {{ process.decision_set.count }} of {{ process.split_count }} completed
20 | """
21 |
22 | start = (
23 | flow.Start(
24 | CreateProcessView,
25 | fields=['question', 'split_count'],
26 | task_result_summary="Asks for {{ process.split_count }} decisions")
27 | .Permission(auto_create=True)
28 | .Next(this.spit_on_decision)
29 | )
30 |
31 | spit_on_decision = (
32 | DynamicSplit(lambda p: p.split_count)
33 | .IfNone(this.end)
34 | .Next(this.make_decision)
35 | )
36 |
37 | make_decision = (
38 | flow.View(
39 | views.DecisionView,
40 | task_description="Decision required")
41 | .Next(this.join_on_decision)
42 | )
43 |
44 | join_on_decision = flow.Join().Next(this.end)
45 |
46 | end = flow.End()
47 |
48 | frontend.register(DynamicSplitFlow)
49 |
--------------------------------------------------------------------------------
/demo/customnode/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.11.7 on 2017-11-22 08:56
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 | migrations.swappable_dependency(settings.AUTH_USER_MODEL),
16 | ('viewflow', '0006_i18n'),
17 | ]
18 |
19 | operations = [
20 | migrations.CreateModel(
21 | name='Decision',
22 | fields=[
23 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
24 | ('decision', models.BooleanField(default=False)),
25 | ],
26 | ),
27 | migrations.CreateModel(
28 | name='DynamicSplitProcess',
29 | fields=[
30 | ('process_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='viewflow.Process')),
31 | ('question', models.CharField(max_length=50)),
32 | ('split_count', models.IntegerField(default=0)),
33 | ],
34 | options={
35 | 'abstract': False,
36 | },
37 | bases=('viewflow.process',),
38 | ),
39 | migrations.AddField(
40 | model_name='decision',
41 | name='process',
42 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='customnode.DynamicSplitProcess'),
43 | ),
44 | migrations.AddField(
45 | model_name='decision',
46 | name='user',
47 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL),
48 | ),
49 | ]
50 |
--------------------------------------------------------------------------------
/demo/customnode/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/customnode/migrations/__init__.py
--------------------------------------------------------------------------------
/demo/customnode/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from django.conf import settings
3 | from viewflow.models import Process
4 |
5 |
6 | class DynamicSplitProcess(Process):
7 | question = models.CharField(max_length=50)
8 | split_count = models.IntegerField(default=0)
9 |
10 |
11 | class Decision(models.Model):
12 | process = models.ForeignKey(DynamicSplitProcess, on_delete=models.CASCADE)
13 | user = models.ForeignKey(
14 | settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.CASCADE)
15 | decision = models.BooleanField(default=False)
16 |
--------------------------------------------------------------------------------
/demo/customnode/nodes.py:
--------------------------------------------------------------------------------
1 | from copy import copy
2 |
3 | from viewflow import Gateway, mixins
4 | from viewflow.exceptions import FlowRuntimeError
5 | from viewflow.activation import AbstractGateActivation
6 | from viewflow.token import Token
7 | from viewflow.flow import views
8 |
9 |
10 | class DynamicSplitActivation(AbstractGateActivation):
11 | def calculate_next(self):
12 | self._split_count = self.flow_task._task_count_callback(self.process)
13 |
14 | def activate_next(self):
15 | if self._split_count:
16 | token_source = Token.split_token_source(self.task.token, self.task.pk)
17 | for _ in range(self._split_count):
18 | self.flow_task._next.activate(prev_activation=self, token=next(token_source))
19 | elif self.flow_task._ifnone_next_node is not None:
20 | self.flow_task._ifnone_next_node.activate(prev_activation=self, token=self.task.token)
21 | else:
22 | raise FlowRuntimeError("{} activated with zero and no IfNone nodes specified".format(self.flow_task.name))
23 |
24 |
25 | class DynamicSplit(mixins.NextNodeMixin,
26 | mixins.UndoViewMixin,
27 | mixins.CancelViewMixin,
28 | mixins.PerformViewMixin,
29 | mixins.DetailViewMixin,
30 | Gateway):
31 | """
32 | Activates several outgoing task instances depends on callback value
33 |
34 | Example::
35 |
36 | spit_on_decision = flow.DynamicSplit(lambda p: 4) \\
37 | .Next(this.make_decision)
38 |
39 | make_decision = flow.View(MyView) \\
40 | .Next(this.join_on_decision)
41 |
42 | join_on_decision = flow.Join() \\
43 | .Next(this.end)
44 | """
45 | task_type = 'SPLIT'
46 |
47 | cancel_view_class = views.CancelTaskView
48 | detail_view_class = views.DetailTaskView
49 | perform_view_class = views.PerformTaskView
50 | undo_view_class = views.UndoTaskView
51 |
52 | activation_class = DynamicSplitActivation
53 |
54 | def __init__(self, callback):
55 | super(DynamicSplit, self).__init__()
56 | self._task_count_callback = callback
57 | self._ifnone_next_node = None
58 |
59 | def _resolve(self, resolver):
60 | super(DynamicSplit, self)._resolve(resolver)
61 | self._ifnone_next_node = resolver.get_implementation(self._ifnone_next_node)
62 |
63 | def IfNone(self, node):
64 | result = copy(self)
65 | result._ifnone_next_node = node
66 | return result
67 |
--------------------------------------------------------------------------------
/demo/customnode/urls.py:
--------------------------------------------------------------------------------
1 | from viewflow.flow.viewset import FlowViewSet
2 | from .flows import DynamicSplitFlow
3 |
4 |
5 | urlpatterns = FlowViewSet(DynamicSplitFlow).urls
6 |
--------------------------------------------------------------------------------
/demo/customnode/views.py:
--------------------------------------------------------------------------------
1 | from django.views import generic
2 | from django.http import HttpResponseRedirect
3 |
4 | from viewflow.flow.views import FlowMixin
5 |
6 | from . import models
7 |
8 |
9 | class DecisionView(FlowMixin, generic.CreateView):
10 | model = models.Decision
11 | fields = ['decision']
12 |
13 | def form_valid(self, form):
14 | self.object = form.save(commit=False)
15 |
16 | self.object.user = self.request.user
17 | self.object.process = self.activation.process
18 | self.object.save()
19 |
20 | self.activation.done()
21 | self.success('Task {task} has been completed.')
22 |
23 | return HttpResponseRedirect(self.get_success_url())
24 |
--------------------------------------------------------------------------------
/demo/employees/__init__.py:
--------------------------------------------------------------------------------
1 | default_app_config = 'demo.employees.apps.EmployeesConfig'
--------------------------------------------------------------------------------
/demo/employees/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | from . import models
4 |
5 |
6 | @admin.register(models.Department)
7 | class DepartmentAdmin(admin.ModelAdmin):
8 | icon = 'account_balance '
9 | list_display = ('dept_no', 'dept_name')
10 |
11 |
12 | @admin.register(models.DeptEmp)
13 | class DeptEmpAdmin(admin.ModelAdmin):
14 | icon = 'people_outline '
15 | list_display = ('employee', 'department', 'from_date', 'to_date')
16 | list_select_related = True
17 | raw_id_fields = ('employee', )
18 | list_filter = ('department', )
19 |
20 |
21 | @admin.register(models.DeptManager)
22 | class DeptManagerAdmin(admin.ModelAdmin):
23 | icon = 'assignment_ind '
24 | list_display = ('employee', 'department', 'from_date', 'to_date')
25 | raw_id_fields = ('employee', )
26 | list_filter = ('department', )
27 |
28 |
29 | @admin.register(models.Employee)
30 | class EmployeeAdmin(admin.ModelAdmin):
31 | icon = 'account_box '
32 | list_display = ('emp_no', 'first_name', 'last_name', 'hire_date')
33 |
34 |
35 | @admin.register(models.Salary)
36 | class SalaryAdmin(admin.ModelAdmin):
37 | icon = 'account_balance_wallet '
38 | list_display = ('employee', 'from_date', 'to_date', 'salary')
39 | raw_id_fields = ('employee', )
40 |
41 |
42 | @admin.register(models.Title)
43 | class TitleAdmin(admin.ModelAdmin):
44 | icon = 'reorder '
45 | list_display = ('employee', 'from_date', 'to_date', 'title')
46 | raw_id_fields = ('employee', )
47 | list_filter = ('title', )
48 |
--------------------------------------------------------------------------------
/demo/employees/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 | from django.utils.translation import ugettext_lazy as _
3 |
4 | from material.frontend.apps import ModuleMixin
5 |
6 |
7 | class EmployeesConfig(ModuleMixin, AppConfig):
8 | name = 'demo.employees'
9 | icon = 'people '
10 | verbose_name = _('Employees')
11 |
12 | def has_perm(self, user):
13 | return user.is_superuser
14 |
--------------------------------------------------------------------------------
/demo/employees/forms.py:
--------------------------------------------------------------------------------
1 | from django import forms
2 | from django.utils.translation import ugettext_lazy as _
3 |
4 | from .models import Employee, DeptManager, Title, Salary
5 |
6 |
7 | class ChangeManagerForm(forms.Form):
8 | manager = forms.ModelChoiceField(queryset=Employee.objects.all()[:100], label=_('Manager'))
9 |
10 | def __init__(self, *args, **kwargs):
11 | self.department = kwargs.pop('department')
12 | super(ChangeManagerForm, self).__init__(*args, **kwargs)
13 |
14 | def save(self):
15 | new_manager = self.cleaned_data['manager']
16 |
17 | DeptManager.objects.filter(
18 | department=self.department
19 | ).set(
20 | department=self.department,
21 | employee=new_manager
22 | )
23 |
24 |
25 | class ChangeTitleForm(forms.Form):
26 | position = forms.CharField(label=_('Position'))
27 |
28 | def __init__(self, *args, **kwargs):
29 | self.employee = kwargs.pop('employee')
30 | super(ChangeTitleForm, self).__init__(*args, **kwargs)
31 |
32 | def save(self):
33 | new_title = self.cleaned_data['position']
34 |
35 | Title.objects.filter(
36 | employee=self.employee,
37 | ).set(
38 | employee=self.employee,
39 | title=new_title
40 | )
41 |
42 |
43 | class ChangeSalaryForm(forms.Form):
44 | salary = forms.IntegerField(max_value=1000000, label=_('Salary'))
45 |
46 | def __init__(self, *args, **kwargs):
47 | self.employee = kwargs.pop('employee')
48 | super(ChangeSalaryForm, self).__init__(*args, **kwargs)
49 |
50 | def save(self):
51 | new_salary = self.cleaned_data['salary']
52 |
53 | Salary.objects.filter(
54 | employee=self.employee,
55 | ).set(
56 | employee=self.employee,
57 | salary=new_salary,
58 | )
59 |
--------------------------------------------------------------------------------
/demo/employees/locale/de/LC_MESSAGES/django.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/employees/locale/de/LC_MESSAGES/django.mo
--------------------------------------------------------------------------------
/demo/employees/locale/de/LC_MESSAGES/django.po:
--------------------------------------------------------------------------------
1 | # distributed under the same license as the Django Material package.
2 | msgid ""
3 | msgstr ""
4 | "Project-Id-Version: django-material\n"
5 | "Report-Msgid-Bugs-To: \n"
6 | "POT-Creation-Date: 2017-05-09 09:52+0000\n"
7 | "Language: de\n"
8 | "MIME-Version: 1.0\n"
9 | "Content-Type: text/plain; charset=UTF-8\n"
10 | "Content-Transfer-Encoding: 8bit\n"
11 | "Plural-Forms: nplurals=2; plural=(n != 1);\n"
12 |
13 | #: apps.py:10 templates/employees/department_employees.html:7
14 | #: templates/employees/menu.html:4
15 | msgid "Employees"
16 | msgstr "Mitarbeiter"
17 |
18 | #: forms.py:8
19 | msgid "manager"
20 | msgstr ""
21 |
22 | #: forms.py:26
23 | msgid "position"
24 | msgstr ""
25 |
26 | #: forms.py:44 models.py:76 models.py:85
27 | msgid "salary"
28 | msgstr "gehalt"
29 |
30 | #: models.py:11
31 | msgid "code"
32 | msgstr ""
33 |
34 | #: models.py:12
35 | msgid "name"
36 | msgstr ""
37 |
38 | #: models.py:15 models.py:27 models.py:42
39 | msgid "department"
40 | msgstr "abteilung"
41 |
42 | #: models.py:16
43 | msgid "departments"
44 | msgstr "Abteilungen"
45 |
46 | #: models.py:26 models.py:41 models.py:65 models.py:75 models.py:91
47 | msgid "employee"
48 | msgstr "mitarbeiter"
49 |
50 | #: models.py:28 models.py:43 models.py:77 models.py:93
51 | msgid "from"
52 | msgstr "aus"
53 |
54 | #: models.py:29 models.py:44 models.py:78 models.py:94
55 | msgid "to"
56 | msgstr "bis"
57 |
58 | #: models.py:34
59 | msgid "department employee"
60 | msgstr "abteilungsmitarbeiter"
61 |
62 | #: models.py:35
63 | msgid "department employees"
64 | msgstr "abteilungsmitarbeiter"
65 |
66 | #: models.py:49
67 | msgid "department manager"
68 | msgstr "abteilungsleiter"
69 |
70 | #: models.py:50
71 | msgid "department managers"
72 | msgstr "abteilungsleiter"
73 |
74 | #: models.py:57
75 | msgid "employee number"
76 | msgstr "mitarbeiternummer"
77 |
78 | #: models.py:58
79 | msgid "birthday"
80 | msgstr "geburtstag"
81 |
82 | #: models.py:59
83 | msgid "first name"
84 | msgstr "vorname"
85 |
86 | #: models.py:60
87 | msgid "last name"
88 | msgstr "nachname"
89 |
90 | #: models.py:61
91 | msgid "gender"
92 | msgstr "geschlecht"
93 |
94 | #: models.py:62
95 | msgid "hire date"
96 | msgstr "anstellungsdatum"
97 |
98 | #: models.py:66 views.py:137
99 | msgid "employees"
100 | msgstr "mitarbeiter"
101 |
102 | #: models.py:86
103 | msgid "salaries"
104 | msgstr "gehälter"
105 |
106 | #: models.py:92 models.py:99
107 | msgid "title"
108 | msgstr "titel"
109 |
110 | #: models.py:100
111 | msgid "titles"
112 | msgstr "titeln"
113 |
114 | #: templates/employees/change_manager.html:7
115 | msgid "Change Manager"
116 | msgstr "manager ändern"
117 |
118 | #: templates/employees/change_salary.html:7
119 | msgid "Change Salary"
120 | msgstr "gehalt ändern"
121 |
122 | #: templates/employees/change_salary.html:14 views.py:39
123 | msgid "Salary History"
124 | msgstr "Gehaltsgeschichte"
125 |
126 | #: templates/employees/change_salary.html:43
127 | msgid "Set new Salary"
128 | msgstr "Neues Gehalt setzen"
129 |
130 | #: templates/employees/change_title.html:7
131 | msgid "Change Title"
132 | msgstr "Titel ändern"
133 |
134 | #: templates/employees/change_title.html:16
135 | #: templates/employees/employee_detail.html:29
136 | msgid "Positions"
137 | msgstr "Positionen"
138 |
139 | #: templates/employees/change_title.html:20
140 | #: templates/employees/employee_detail.html:33
141 | msgid "Position"
142 | msgstr "Position"
143 |
144 | #: templates/employees/change_title.html:21
145 | #: templates/employees/department_detail.html:42
146 | #: templates/employees/employee_detail.html:34
147 | #: templates/employees/employee_detail.html:60
148 | #: templates/employees/employee_detail.html:85
149 | msgid "Since"
150 | msgstr "seit"
151 |
152 | #: templates/employees/change_title.html:22
153 | #: templates/employees/employee_detail.html:35
154 | #: templates/employees/employee_detail.html:61
155 | msgid "To"
156 | msgstr "Bis"
157 |
158 | #: templates/employees/change_title.html:38
159 | #: templates/employees/department_detail.html:29
160 | #: templates/employees/department_detail.html:56
161 | #: templates/employees/employee_detail.html:23
162 | #: templates/employees/employee_detail.html:50
163 | #: templates/employees/employee_detail.html:99
164 | msgid "Change"
165 | msgstr "Ändern"
166 |
167 | #: templates/employees/department_detail.html:28
168 | #: templates/employees/employee_detail.html:22
169 | msgid "Delete"
170 | msgstr "Löschen"
171 |
172 | #: templates/employees/department_detail.html:37
173 | msgid "Department Managers"
174 | msgstr "Abteilungsleiter"
175 |
176 | #: templates/employees/department_detail.html:41
177 | msgid "Manager"
178 | msgstr ""
179 |
180 | #: templates/employees/employee_detail.html:55 templates/employees/menu.html:3
181 | msgid "Departments"
182 | msgstr "Abteilungen"
183 |
184 | #: templates/employees/employee_detail.html:59
185 | msgid "Department"
186 | msgstr "Abteilung"
187 |
188 | #: templates/employees/employee_detail.html:80
189 | #: templates/employees/employee_detail.html:84
190 | msgid "Salary"
191 | msgstr "Gehalt"
192 |
193 | #: views.py:107
194 | msgid "current salary"
195 | msgstr "Aktuelles gehalt"
196 |
--------------------------------------------------------------------------------
/demo/employees/locale/es/LC_MESSAGES/django.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/employees/locale/es/LC_MESSAGES/django.mo
--------------------------------------------------------------------------------
/demo/employees/locale/fr/LC_MESSAGES/django.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/employees/locale/fr/LC_MESSAGES/django.mo
--------------------------------------------------------------------------------
/demo/employees/locale/fr/LC_MESSAGES/django.po:
--------------------------------------------------------------------------------
1 | # distributed under the same license as the Django Material package.
2 | msgid ""
3 | msgstr ""
4 | "Project-Id-Version: django-material\n"
5 | "Report-Msgid-Bugs-To: \n"
6 | "POT-Creation-Date: 2017-05-09 09:52+0000\n"
7 | "Language: fr\n"
8 | "MIME-Version: 1.0\n"
9 | "Content-Type: text/plain; charset=UTF-8\n"
10 | "Content-Transfer-Encoding: 8bit\n"
11 | "Plural-Forms: nplurals=2; plural=(n > 1);\n"
12 |
13 | #: apps.py:10 templates/employees/department_employees.html:7
14 | #: templates/employees/menu.html:4
15 | msgid "Employees"
16 | msgstr "Employés"
17 |
18 | #: forms.py:8
19 | msgid "manager"
20 | msgstr "directeur"
21 |
22 | #: forms.py:26
23 | msgid "position"
24 | msgstr "titre"
25 |
26 | #: forms.py:44 models.py:76 models.py:85
27 | msgid "salary"
28 | msgstr "un salaire"
29 |
30 | #: models.py:11
31 | msgid "code"
32 | msgstr ""
33 |
34 | #: models.py:12
35 | msgid "name"
36 | msgstr "prénom"
37 |
38 | #: models.py:15 models.py:27 models.py:42
39 | msgid "department"
40 | msgstr "département"
41 |
42 | #: models.py:16
43 | msgid "departments"
44 | msgstr "départements"
45 |
46 | #: models.py:26 models.py:41 models.py:65 models.py:75 models.py:91
47 | msgid "employee"
48 | msgstr "employé"
49 |
50 | #: models.py:28 models.py:43 models.py:77 models.py:93
51 | msgid "from"
52 | msgstr "de"
53 |
54 | #: models.py:29 models.py:44 models.py:78 models.py:94
55 | msgid "to"
56 | msgstr "à"
57 |
58 | #: models.py:34
59 | msgid "department employee"
60 | msgstr "employé du département"
61 |
62 | #: models.py:35
63 | msgid "department employees"
64 | msgstr "employés du département"
65 |
66 | #: models.py:49
67 | msgid "department manager"
68 | msgstr "gestionnaire département"
69 |
70 | #: models.py:50
71 | msgid "department managers"
72 | msgstr "directeurs de département"
73 |
74 | #: models.py:57
75 | msgid "employee number"
76 | msgstr "numéro d'employé"
77 |
78 | #: models.py:58
79 | msgid "birthday"
80 | msgstr "anniversaire"
81 |
82 | #: models.py:59
83 | msgid "first name"
84 | msgstr "prénom"
85 |
86 | #: models.py:60
87 | msgid "last name"
88 | msgstr "nom de famille"
89 |
90 | #: models.py:61
91 | msgid "gender"
92 | msgstr "le genre"
93 |
94 | #: models.py:62
95 | msgid "hire date"
96 | msgstr "date d'embauche"
97 |
98 | #: models.py:66 views.py:137
99 | msgid "employees"
100 | msgstr "employés"
101 |
102 | #: models.py:86
103 | msgid "salaries"
104 | msgstr "les salaires"
105 |
106 | #: models.py:92 models.py:99
107 | msgid "title"
108 | msgstr "titre"
109 |
110 | #: models.py:100
111 | msgid "titles"
112 | msgstr "Titres"
113 |
114 | #: templates/employees/change_manager.html:7
115 | msgid "Change Manager"
116 | msgstr "Changer de directeur"
117 |
118 | #: templates/employees/change_salary.html:7
119 | msgid "Change Salary"
120 | msgstr "Changer de salaire"
121 |
122 | #: templates/employees/change_salary.html:14 views.py:39
123 | msgid "Salary History"
124 | msgstr "Historique des salaires"
125 |
126 | #: templates/employees/change_salary.html:43
127 | msgid "Set new Salary"
128 | msgstr "Nouveau salaire"
129 |
130 | #: templates/employees/change_title.html:7
131 | msgid "Change Title"
132 | msgstr "Modifier le titre"
133 |
134 | #: templates/employees/change_title.html:16
135 | #: templates/employees/employee_detail.html:29
136 | msgid "Positions"
137 | msgstr "Titres"
138 |
139 | #: templates/employees/change_title.html:20
140 | #: templates/employees/employee_detail.html:33
141 | msgid "Position"
142 | msgstr "Titre"
143 |
144 | #: templates/employees/change_title.html:21
145 | #: templates/employees/department_detail.html:42
146 | #: templates/employees/employee_detail.html:34
147 | #: templates/employees/employee_detail.html:60
148 | #: templates/employees/employee_detail.html:85
149 | msgid "Since"
150 | msgstr "Depuis"
151 |
152 | #: templates/employees/change_title.html:22
153 | #: templates/employees/employee_detail.html:35
154 | #: templates/employees/employee_detail.html:61
155 | msgid "To"
156 | msgstr "À"
157 |
158 | #: templates/employees/change_title.html:38
159 | #: templates/employees/department_detail.html:29
160 | #: templates/employees/department_detail.html:56
161 | #: templates/employees/employee_detail.html:23
162 | #: templates/employees/employee_detail.html:50
163 | #: templates/employees/employee_detail.html:99
164 | msgid "Change"
165 | msgstr ""
166 |
167 | #: templates/employees/department_detail.html:28
168 | #: templates/employees/employee_detail.html:22
169 | msgid "Delete"
170 | msgstr ""
171 |
172 | #: templates/employees/department_detail.html:37
173 | msgid "Department Managers"
174 | msgstr "Directeurs de département"
175 |
176 | #: templates/employees/department_detail.html:41
177 | msgid "Manager"
178 | msgstr "Directeur"
179 |
180 | #: templates/employees/employee_detail.html:55 templates/employees/menu.html:3
181 | msgid "Departments"
182 | msgstr "Départements"
183 |
184 | #: templates/employees/employee_detail.html:59
185 | msgid "Department"
186 | msgstr "Département"
187 |
188 | #: templates/employees/employee_detail.html:80
189 | #: templates/employees/employee_detail.html:84
190 | msgid "Salary"
191 | msgstr "Un salaire"
192 |
193 | #: views.py:107
194 | msgid "current salary"
195 | msgstr "salaire actuel"
196 |
--------------------------------------------------------------------------------
/demo/employees/locale/ko/LC_MESSAGES/django.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/employees/locale/ko/LC_MESSAGES/django.mo
--------------------------------------------------------------------------------
/demo/employees/locale/ko/LC_MESSAGES/django.po:
--------------------------------------------------------------------------------
1 | # distributed under the same license as the Django Material package.
2 | msgid ""
3 | msgstr ""
4 | "Project-Id-Version: django-material\n"
5 | "Report-Msgid-Bugs-To: \n"
6 | "POT-Creation-Date: 2017-05-09 09:52+0000\n"
7 | "Language: ko\n"
8 | "MIME-Version: 1.0\n"
9 | "Content-Type: text/plain; charset=UTF-8\n"
10 | "Content-Transfer-Encoding: 8bit\n"
11 | "Plural-Forms: nplurals=1; plural=0;\n"
12 |
13 | #: apps.py:10 templates/employees/department_employees.html:7
14 | #: templates/employees/menu.html:4
15 | msgid "Employees"
16 | msgstr "직원"
17 |
18 | #: forms.py:8
19 | msgid "manager"
20 | msgstr "매니저"
21 |
22 | #: forms.py:26
23 | msgid "position"
24 | msgstr "위치"
25 |
26 | #: forms.py:44 models.py:76 models.py:85
27 | msgid "salary"
28 | msgstr "봉급"
29 |
30 | #: models.py:11
31 | msgid "code"
32 | msgstr "암호"
33 |
34 | #: models.py:12
35 | msgid "name"
36 | msgstr "이름"
37 |
38 | #: models.py:15 models.py:27 models.py:42
39 | msgid "department"
40 | msgstr "학과"
41 |
42 | #: models.py:16
43 | msgid "departments"
44 | msgstr "부서"
45 |
46 | #: models.py:26 models.py:41 models.py:65 models.py:75 models.py:91
47 | msgid "employee"
48 | msgstr "종업원"
49 |
50 | #: models.py:28 models.py:43 models.py:77 models.py:93
51 | msgid "from"
52 | msgstr "부터"
53 |
54 | #: models.py:29 models.py:44 models.py:78 models.py:94
55 | msgid "to"
56 | msgstr "에"
57 |
58 | #: models.py:34
59 | msgid "department employee"
60 | msgstr "부서 직원"
61 |
62 | #: models.py:35
63 | msgid "department employees"
64 | msgstr "부서 직원"
65 |
66 | #: models.py:49
67 | msgid "department manager"
68 | msgstr "부서 관리자"
69 |
70 | #: models.py:50
71 | msgid "department managers"
72 | msgstr "부서 관리자"
73 |
74 | #: models.py:57
75 | msgid "employee number"
76 | msgstr "직원 번호"
77 |
78 | #: models.py:58
79 | msgid "birthday"
80 | msgstr "생일"
81 |
82 | #: models.py:59
83 | msgid "first name"
84 | msgstr "이름"
85 |
86 | #: models.py:60
87 | msgid "last name"
88 | msgstr "성"
89 |
90 | #: models.py:61
91 | msgid "gender"
92 | msgstr "성별"
93 |
94 | #: models.py:62
95 | msgid "hire date"
96 | msgstr "고용 날짜"
97 |
98 | #: models.py:66 views.py:137
99 | msgid "employees"
100 | msgstr "직원"
101 |
102 | #: models.py:86
103 | msgid "salaries"
104 | msgstr "급여"
105 |
106 | #: models.py:92 models.py:99
107 | msgid "title"
108 | msgstr "표제"
109 |
110 | #: models.py:100
111 | msgid "titles"
112 | msgstr "제목들"
113 |
114 | #: templates/employees/change_manager.html:7
115 | msgid "Change Manager"
116 | msgstr "변경 관리자"
117 |
118 | #: templates/employees/change_salary.html:7
119 | msgid "Change Salary"
120 | msgstr "연봉 변경"
121 |
122 | #: templates/employees/change_salary.html:14 views.py:39
123 | msgid "Salary History"
124 | msgstr "연봉 연혁"
125 |
126 | #: templates/employees/change_salary.html:43
127 | msgid "Set new Salary"
128 | msgstr "새 급여"
129 |
130 | #: templates/employees/change_title.html:7
131 | msgid "Change Title"
132 | msgstr "제목 변경"
133 |
134 | #: templates/employees/change_title.html:16
135 | #: templates/employees/employee_detail.html:29
136 | msgid "Positions"
137 | msgstr "직책"
138 |
139 | #: templates/employees/change_title.html:20
140 | #: templates/employees/employee_detail.html:33
141 | msgid "Position"
142 | msgstr "위치"
143 |
144 | #: templates/employees/change_title.html:21
145 | #: templates/employees/department_detail.html:42
146 | #: templates/employees/employee_detail.html:34
147 | #: templates/employees/employee_detail.html:60
148 | #: templates/employees/employee_detail.html:85
149 | msgid "Since"
150 | msgstr "이후"
151 |
152 | #: templates/employees/change_title.html:22
153 | #: templates/employees/employee_detail.html:35
154 | #: templates/employees/employee_detail.html:61
155 | msgid "To"
156 | msgstr "에"
157 |
158 | #: templates/employees/change_title.html:38
159 | #: templates/employees/department_detail.html:29
160 | #: templates/employees/department_detail.html:56
161 | #: templates/employees/employee_detail.html:23
162 | #: templates/employees/employee_detail.html:50
163 | #: templates/employees/employee_detail.html:99
164 | msgid "Change"
165 | msgstr ""
166 |
167 | #: templates/employees/department_detail.html:28
168 | #: templates/employees/employee_detail.html:22
169 | msgid "Delete"
170 | msgstr ""
171 |
172 | #: templates/employees/department_detail.html:37
173 | msgid "Department Managers"
174 | msgstr "부서 관리자"
175 |
176 | #: templates/employees/department_detail.html:41
177 | msgid "Manager"
178 | msgstr "매니저"
179 |
180 | #: templates/employees/employee_detail.html:55 templates/employees/menu.html:3
181 | msgid "Departments"
182 | msgstr "학과"
183 |
184 | #: templates/employees/employee_detail.html:59
185 | msgid "Department"
186 | msgstr "학과"
187 |
188 | #: templates/employees/employee_detail.html:80
189 | #: templates/employees/employee_detail.html:84
190 | msgid "Salary"
191 | msgstr "봉급"
192 |
193 | #: views.py:107
194 | msgid "current salary"
195 | msgstr "현재 급여"
196 |
--------------------------------------------------------------------------------
/demo/employees/locale/ru/LC_MESSAGES/django.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/employees/locale/ru/LC_MESSAGES/django.mo
--------------------------------------------------------------------------------
/demo/employees/locale/zh_Hans/LC_MESSAGES/django.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/employees/locale/zh_Hans/LC_MESSAGES/django.mo
--------------------------------------------------------------------------------
/demo/employees/locale/zh_Hans/LC_MESSAGES/django.po:
--------------------------------------------------------------------------------
1 | # distributed under the same license as the Django Material package.
2 | msgid ""
3 | msgstr ""
4 | "Project-Id-Version: django-material\n"
5 | "Report-Msgid-Bugs-To: \n"
6 | "POT-Creation-Date: 2017-05-09 09:52+0000\n"
7 | "Language: zh_CN\n"
8 | "MIME-Version: 1.0\n"
9 | "Content-Type: text/plain; charset=UTF-8\n"
10 | "Content-Transfer-Encoding: 8bit\n"
11 | "Plural-Forms: nplurals=1; plural=0;\n"
12 |
13 | #: apps.py:10 templates/employees/department_employees.html:7
14 | #: templates/employees/menu.html:4
15 | msgid "Employees"
16 | msgstr "雇员"
17 |
18 | #: forms.py:8
19 | msgid "manager"
20 | msgstr "经理"
21 |
22 | #: forms.py:26
23 | msgid "position"
24 | msgstr "位置"
25 |
26 | #: forms.py:44 models.py:76 models.py:85
27 | msgid "salary"
28 | msgstr "薪水"
29 |
30 | #: models.py:11
31 | msgid "code"
32 | msgstr "码"
33 |
34 | #: models.py:12
35 | msgid "name"
36 | msgstr "名称"
37 |
38 | #: models.py:15 models.py:27 models.py:42
39 | msgid "department"
40 | msgstr "部"
41 |
42 | #: models.py:16
43 | msgid "departments"
44 | msgstr "部门"
45 |
46 | #: models.py:26 models.py:41 models.py:65 models.py:75 models.py:91
47 | msgid "employee"
48 | msgstr "雇员"
49 |
50 | #: models.py:28 models.py:43 models.py:77 models.py:93
51 | msgid "from"
52 | msgstr "自"
53 |
54 | #: models.py:29 models.py:44 models.py:78 models.py:94
55 | msgid "to"
56 | msgstr "至"
57 |
58 | #: models.py:34
59 | msgid "department employee"
60 | msgstr "部门员工"
61 |
62 | #: models.py:35
63 | msgid "department employees"
64 | msgstr "部门员工"
65 |
66 | #: models.py:49
67 | msgid "department manager"
68 | msgstr "部门经理"
69 |
70 | #: models.py:50
71 | msgid "department managers"
72 | msgstr "部门经理"
73 |
74 | #: models.py:57
75 | msgid "employee number"
76 | msgstr "员工编号"
77 |
78 | #: models.py:58
79 | msgid "birthday"
80 | msgstr "生日"
81 |
82 | #: models.py:59
83 | msgid "first name"
84 | msgstr "名字"
85 |
86 | #: models.py:60
87 | msgid "last name"
88 | msgstr "姓"
89 |
90 | #: models.py:61
91 | msgid "gender"
92 | msgstr "性别"
93 |
94 | #: models.py:62
95 | msgid "hire date"
96 | msgstr "聘用日期"
97 |
98 | #: models.py:66 views.py:137
99 | msgid "employees"
100 | msgstr "雇员"
101 |
102 | #: models.py:86
103 | msgid "salaries"
104 | msgstr "工资"
105 |
106 | #: models.py:92 models.py:99
107 | msgid "title"
108 | msgstr "标题"
109 |
110 | #: models.py:100
111 | msgid "titles"
112 | msgstr "标题"
113 |
114 | #: templates/employees/change_manager.html:7
115 | msgid "Change Manager"
116 | msgstr "更改"
117 |
118 | #: templates/employees/change_salary.html:7
119 | msgid "Change Salary"
120 | msgstr "换薪水"
121 |
122 | #: templates/employees/change_salary.html:14 views.py:39
123 | msgid "Salary History"
124 | msgstr "工资历史"
125 |
126 | #: templates/employees/change_salary.html:43
127 | msgid "Set new Salary"
128 | msgstr "新工资"
129 |
130 | #: templates/employees/change_title.html:7
131 | msgid "Change Title"
132 | msgstr "更改标题"
133 |
134 | #: templates/employees/change_title.html:16
135 | #: templates/employees/employee_detail.html:29
136 | msgid "Positions"
137 | msgstr "位置"
138 |
139 | #: templates/employees/change_title.html:20
140 | #: templates/employees/employee_detail.html:33
141 | msgid "Position"
142 | msgstr "位置"
143 |
144 | #: templates/employees/change_title.html:21
145 | #: templates/employees/department_detail.html:42
146 | #: templates/employees/employee_detail.html:34
147 | #: templates/employees/employee_detail.html:60
148 | #: templates/employees/employee_detail.html:85
149 | msgid "Since"
150 | msgstr "自"
151 |
152 | #: templates/employees/change_title.html:22
153 | #: templates/employees/employee_detail.html:35
154 | #: templates/employees/employee_detail.html:61
155 | msgid "To"
156 | msgstr "至"
157 |
158 | #: templates/employees/change_title.html:38
159 | #: templates/employees/department_detail.html:29
160 | #: templates/employees/department_detail.html:56
161 | #: templates/employees/employee_detail.html:23
162 | #: templates/employees/employee_detail.html:50
163 | #: templates/employees/employee_detail.html:99
164 | msgid "Change"
165 | msgstr ""
166 |
167 | #: templates/employees/department_detail.html:28
168 | #: templates/employees/employee_detail.html:22
169 | msgid "Delete"
170 | msgstr ""
171 |
172 | #: templates/employees/department_detail.html:37
173 | msgid "Department Managers"
174 | msgstr "部门经理"
175 |
176 | #: templates/employees/department_detail.html:41
177 | msgid "Manager"
178 | msgstr "经理"
179 |
180 | #: templates/employees/employee_detail.html:55 templates/employees/menu.html:3
181 | msgid "Departments"
182 | msgstr "部门"
183 |
184 | #: templates/employees/employee_detail.html:59
185 | msgid "Department"
186 | msgstr "部"
187 |
188 | #: templates/employees/employee_detail.html:80
189 | #: templates/employees/employee_detail.html:84
190 | msgid "Salary"
191 | msgstr "薪水"
192 |
193 | #: views.py:107
194 | msgid "current salary"
195 | msgstr "当前工资"
196 |
--------------------------------------------------------------------------------
/demo/employees/managers.py:
--------------------------------------------------------------------------------
1 | from datetime import date
2 |
3 | from django.db import models
4 | from django.utils import timezone
5 |
6 |
7 | class TemporalQuerySet(models.QuerySet):
8 | """Temporal manager for models with `from_date`/`to_date` fields."""
9 |
10 | def set(self, **kwargs):
11 | today = timezone.now().date()
12 |
13 | self.filter(
14 | from_date__lte=today,
15 | to_date__gt=today,
16 | ).update(to_date=today)
17 |
18 | self.filter(
19 | from_date=today,
20 | to_date=today,
21 | ).delete()
22 |
23 | return self.create(
24 | from_date=today,
25 | to_date=date(9999, 1, 1),
26 | **kwargs
27 | )
28 |
29 | def current(self):
30 | today = timezone.now().date()
31 |
32 | return self.filter(
33 | from_date__lte=today,
34 | to_date__gt=today,
35 | ).first()
36 |
--------------------------------------------------------------------------------
/demo/employees/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.10.2 on 2016-12-20 08:19
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='Department',
19 | fields=[
20 | ('dept_no', models.CharField(max_length=4, primary_key=True, serialize=False)),
21 | ('dept_name', models.CharField(max_length=40, unique=True)),
22 | ],
23 | options={
24 | 'ordering': ['dept_no'],
25 | 'db_table': 'departments',
26 | },
27 | ),
28 | migrations.CreateModel(
29 | name='DeptEmp',
30 | fields=[
31 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
32 | ('from_date', models.DateField()),
33 | ('to_date', models.DateField()),
34 | ('department', models.ForeignKey(db_column='dept_no', on_delete=django.db.models.deletion.DO_NOTHING, to='employees.Department')),
35 | ],
36 | options={
37 | 'db_table': 'dept_emp',
38 | },
39 | ),
40 | migrations.CreateModel(
41 | name='DeptManager',
42 | fields=[
43 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
44 | ('from_date', models.DateField()),
45 | ('to_date', models.DateField()),
46 | ('department', models.ForeignKey(db_column='dept_no', on_delete=django.db.models.deletion.DO_NOTHING, to='employees.Department')),
47 | ],
48 | options={
49 | 'ordering': ['-from_date'],
50 | 'db_table': 'dept_manager',
51 | },
52 | ),
53 | migrations.CreateModel(
54 | name='Employee',
55 | fields=[
56 | ('emp_no', models.IntegerField(primary_key=True, serialize=False)),
57 | ('birth_date', models.DateField()),
58 | ('first_name', models.CharField(max_length=14)),
59 | ('last_name', models.CharField(max_length=16)),
60 | ('gender', models.CharField(max_length=1)),
61 | ('hire_date', models.DateField()),
62 | ],
63 | options={
64 | 'db_table': 'employees',
65 | },
66 | ),
67 | migrations.CreateModel(
68 | name='Salary',
69 | fields=[
70 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
71 | ('salary', models.IntegerField()),
72 | ('from_date', models.DateField()),
73 | ('to_date', models.DateField()),
74 | ('employee', models.ForeignKey(db_column='emp_no', on_delete=django.db.models.deletion.DO_NOTHING, to='employees.Employee')),
75 | ],
76 | options={
77 | 'verbose_name': 'Salary',
78 | 'verbose_name_plural': 'Salaries',
79 | 'ordering': ['-from_date'],
80 | 'db_table': 'salaries',
81 | },
82 | ),
83 | migrations.CreateModel(
84 | name='Title',
85 | fields=[
86 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
87 | ('title', models.CharField(max_length=50)),
88 | ('from_date', models.DateField()),
89 | ('to_date', models.DateField(blank=True, null=True)),
90 | ('employee', models.ForeignKey(db_column='emp_no', on_delete=django.db.models.deletion.DO_NOTHING, to='employees.Employee')),
91 | ],
92 | options={
93 | 'db_table': 'titles',
94 | },
95 | ),
96 | migrations.AddField(
97 | model_name='deptmanager',
98 | name='employee',
99 | field=models.ForeignKey(db_column='emp_no', on_delete=django.db.models.deletion.DO_NOTHING, to='employees.Employee'),
100 | ),
101 | migrations.AddField(
102 | model_name='deptemp',
103 | name='employee',
104 | field=models.ForeignKey(db_column='emp_no', on_delete=django.db.models.deletion.DO_NOTHING, to='employees.Employee'),
105 | ),
106 | ]
107 |
--------------------------------------------------------------------------------
/demo/employees/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/employees/migrations/__init__.py
--------------------------------------------------------------------------------
/demo/employees/models.py:
--------------------------------------------------------------------------------
1 | from __future__ import unicode_literals
2 |
3 | from django.db import models
4 | from django.utils.encoding import python_2_unicode_compatible
5 | from django.utils.translation import ugettext_lazy as _
6 | from .managers import TemporalQuerySet
7 |
8 |
9 | @python_2_unicode_compatible
10 | class Department(models.Model):
11 | dept_no = models.CharField(_('code'), primary_key=True, max_length=4)
12 | dept_name = models.CharField(_('name'), unique=True, max_length=40)
13 |
14 | class Meta:
15 | verbose_name = _('department')
16 | verbose_name_plural = _('departments')
17 | db_table = 'departments'
18 | ordering = ['dept_no']
19 |
20 | def __str__(self):
21 | return self.dept_name
22 |
23 |
24 | @python_2_unicode_compatible
25 | class DeptEmp(models.Model):
26 | employee = models.ForeignKey('Employee', on_delete=models.CASCADE, db_column='emp_no', verbose_name=_('employee'))
27 | department = models.ForeignKey(Department, on_delete=models.CASCADE, db_column='dept_no', verbose_name=_('department'))
28 | from_date = models.DateField(_('from'))
29 | to_date = models.DateField(_('to'))
30 |
31 | objects = TemporalQuerySet.as_manager()
32 |
33 | class Meta:
34 | verbose_name = _('department employee')
35 | verbose_name_plural = _('department employees')
36 | db_table = 'dept_emp'
37 |
38 | def __str__(self):
39 | return "{} - {}".format(self.employee, self.department)
40 |
41 |
42 | @python_2_unicode_compatible
43 | class DeptManager(models.Model):
44 | employee = models.ForeignKey('Employee', on_delete=models.CASCADE, db_column='emp_no', verbose_name=_('employee'))
45 | department = models.ForeignKey(Department, on_delete=models.CASCADE, db_column='dept_no', verbose_name=_('department'))
46 | from_date = models.DateField(_('from'))
47 | to_date = models.DateField(_('to'))
48 |
49 | objects = TemporalQuerySet.as_manager()
50 |
51 | class Meta:
52 | verbose_name = _('department manager')
53 | verbose_name_plural = _('department managers')
54 | db_table = 'dept_manager'
55 | ordering = ['-from_date']
56 |
57 | def __str__(self):
58 | return "{} - {}".format(self.employee, self.department)
59 |
60 |
61 | @python_2_unicode_compatible
62 | class Employee(models.Model):
63 | emp_no = models.IntegerField(_('employee number'), primary_key=True)
64 | birth_date = models.DateField(_('birthday'))
65 | first_name = models.CharField(_('first name'), max_length=14)
66 | last_name = models.CharField(_('last name'), max_length=16)
67 | gender = models.CharField(_('gender'), max_length=1)
68 | hire_date = models.DateField(_('hire date'))
69 |
70 | class Meta:
71 | verbose_name = _('employee')
72 | verbose_name_plural = _('employees')
73 | db_table = 'employees'
74 |
75 | def __str__(self):
76 | return "{} {}".format(self.first_name, self.last_name)
77 |
78 |
79 | @python_2_unicode_compatible
80 | class Salary(models.Model):
81 | employee = models.ForeignKey(Employee, on_delete=models.CASCADE, db_column='emp_no', verbose_name=_('employee'))
82 | salary = models.IntegerField(_('salary'))
83 | from_date = models.DateField(_('from'))
84 | to_date = models.DateField(_('to'))
85 |
86 | objects = TemporalQuerySet.as_manager()
87 |
88 | class Meta:
89 | db_table = 'salaries'
90 | ordering = ['-from_date']
91 | verbose_name = _('salary')
92 | verbose_name_plural = _('salaries')
93 |
94 | def __str__(self):
95 | return "{} - {}".format(self.employee, self.salary)
96 |
97 |
98 | @python_2_unicode_compatible
99 | class Title(models.Model):
100 | employee = models.ForeignKey(Employee, on_delete=models.CASCADE, db_column='emp_no', verbose_name=_('employee'))
101 | title = models.CharField(_('title'), max_length=50)
102 | from_date = models.DateField(_('from'))
103 | to_date = models.DateField(_('to'), blank=True, null=True)
104 |
105 | objects = TemporalQuerySet.as_manager()
106 |
107 | class Meta:
108 | verbose_name = _('title')
109 | verbose_name_plural = _('titles')
110 | db_table = 'titles'
111 |
112 | def __str__(self):
113 | return "{} - {}".format(self.employee, self.title)
114 |
--------------------------------------------------------------------------------
/demo/employees/templates/employees/base_module.html:
--------------------------------------------------------------------------------
1 | {% extends 'material/frontend/base_module.html' %}
2 |
3 | {% block js %}
4 | {{ block.super }}
5 |
6 | {% endblock %}
7 |
--------------------------------------------------------------------------------
/demo/employees/templates/employees/change_manager.html:
--------------------------------------------------------------------------------
1 | {% extends 'employees/base_module.html' %}
2 | {% load i18n material_frontend %}
3 |
4 | {% block breadcrumbs_items %}
5 | {{ department|verbose_name_plural|title }}
6 | {{ department }}
7 | {% trans 'Change Manager' %}
8 | {% endblock %}
9 |
10 | {% block content %}
11 |
12 |
13 | {{ form }}
14 |
15 |
16 | {% endblock %}
17 |
--------------------------------------------------------------------------------
/demo/employees/templates/employees/change_salary.html:
--------------------------------------------------------------------------------
1 | {% extends 'employees/base_module.html' %}
2 | {% load i18n material_frontend %}
3 |
4 | {% block breadcrumbs_items %}
5 | {{ employee|verbose_name_plural|title }}
6 | {{ employee }}
7 | {% trans 'Change Salary' %}
8 | {% endblock %}
9 |
10 | {% block content %}
11 |
12 |
13 |
14 |
{% trans 'Salary History' %}
15 |
16 |
17 |
30 |
31 |
32 |
33 |
48 | {% endblock %}
49 |
--------------------------------------------------------------------------------
/demo/employees/templates/employees/change_title.html:
--------------------------------------------------------------------------------
1 | {% extends 'employees/base_module.html' %}
2 | {% load i18n material_frontend %}
3 |
4 | {% block breadcrumbs_items %}
5 | {{ employee|verbose_name_plural|title }}
6 | {{ employee }}
7 | {% trans 'Change Title' %}
8 | {% endblock %}
9 |
10 | {% block content %}
11 |
43 | {% endblock %}
44 |
--------------------------------------------------------------------------------
/demo/employees/templates/employees/department_detail.html:
--------------------------------------------------------------------------------
1 | {% extends 'material/frontend/views/detail.html' %}
2 | {% load i18n material_frontend %}
3 |
4 | {% block content %}
5 |
6 |
7 |
8 | {% block card %}
9 |
{{ view.model|verbose_name|title }}: {{ object }}
10 |
11 | {% for field_name, value in object_data %}
12 |
13 | {{ field_name }}
14 | {{ value }}
15 | {% endfor %}
16 |
17 | {% endblock %}
18 |
19 | Employees
20 |
21 | {{ object.deptemp_set.count }}
22 |
23 |
24 |
25 |
26 |
32 |
33 |
34 |
35 |
36 |
37 |
{% trans 'Department Managers' %}
38 |
39 |
40 |
41 | {% trans 'Manager' %}
42 | {% trans 'Since' %}
43 |
44 |
45 |
46 | {% for manager in object.deptmanager_set.all %}
47 |
48 | {{ manager.employee }}
49 | {{ manager.from_date }}
50 |
51 | {% endfor %}
52 |
53 |
54 |
55 |
58 |
59 |
60 | {% endblock %}
61 |
--------------------------------------------------------------------------------
/demo/employees/templates/employees/department_employees.html:
--------------------------------------------------------------------------------
1 | {% extends 'material/frontend/views/list.html' %}
2 | {% load i18n material_frontend %}
3 |
4 | {% block breadcrumbs_items %}
5 | {{ department|verbose_name_plural|title }}
6 | {{ department }}
7 | {% trans 'Employees' %}
8 | {% endblock %}
9 |
--------------------------------------------------------------------------------
/demo/employees/templates/employees/employee_detail.html:
--------------------------------------------------------------------------------
1 | {% extends 'material/frontend/views/detail.html' %}
2 | {% load i18n material_frontend %}
3 |
4 | {% block content %}
5 |
6 |
7 |
8 | {% block card %}
9 |
{{ view.model|verbose_name|title }}: {{ object }}
10 |
11 | {% for field_name, value in object_data %}
12 |
13 | {{ field_name }}
14 | {{ value }}
15 | {% endfor %}
16 |
17 | {% endblock %}
18 |
19 |
20 |
26 |
27 |
28 |
29 |
{% trans 'Positions' %}
30 |
31 |
32 |
33 | {% trans 'Position' %}
34 | {% trans 'Since' %}
35 | {% trans 'To' %}
36 |
37 |
38 |
39 | {% for title in object.title_set.all|slice:":10" %}
40 |
41 | {{ title.title }}
42 | {{ title.from_date }}
43 | {{ title.to_date }}
44 |
45 | {% endfor %}
46 |
47 |
48 |
49 |
52 |
53 |
54 |
55 |
{% trans 'Departments' %}
56 |
57 |
58 |
59 | {% trans 'Department' %}
60 | {% trans 'Since' %}
61 | {% trans 'To' %}
62 |
63 |
64 |
65 | {% for dept in object.deptemp_set.all|slice:":10" %}
66 |
67 | {{ dept.department }}
68 | {{ dept.from_date }}
69 | {{ dept.to_date }}
70 |
71 | {% endfor %}
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
{% trans 'Salary' %}
81 |
82 |
83 |
84 | {% trans 'Salary' %}
85 | {% trans 'Since' %}
86 |
87 |
88 |
89 | {% for salary in object.salary_set.all|slice:":10" %}
90 |
91 | ${{ salary.salary }}
92 | {{ salary.from_date }}
93 |
94 | {% endfor %}
95 |
96 |
97 |
98 |
101 |
102 |
103 | {% endblock %}
104 |
--------------------------------------------------------------------------------
/demo/employees/templates/employees/menu.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}
2 |
6 |
--------------------------------------------------------------------------------
/demo/employees/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url, include
2 | from django.views import generic
3 |
4 | from . import views
5 |
6 |
7 | urlpatterns = [
8 | url('^$', generic.RedirectView.as_view(
9 | url='./departments/'), name="index"),
10 | url('^departments/', include(views.DepartmentViewSet().urls)),
11 | url('^employees/', include(views.EmployeeViewSet().urls)),
12 | ]
13 |
--------------------------------------------------------------------------------
/demo/employees/views.py:
--------------------------------------------------------------------------------
1 | import json
2 | from django.contrib.auth.decorators import login_required
3 | from django.utils import timezone
4 | from django.shortcuts import get_object_or_404, render
5 | from django.utils.translation import ugettext, ugettext_lazy as _
6 |
7 | from material.frontend.views import ModelViewSet, ListModelView
8 |
9 | from . import models, forms
10 |
11 |
12 | @login_required
13 | def change_manager(request, department_pk):
14 | department = get_object_or_404(models.Department, pk=department_pk)
15 | form = forms.ChangeManagerForm(department=department, data=request.POST or None)
16 |
17 | if form.is_valid():
18 | form.save()
19 |
20 | return render(request, 'employees/change_manager.html', {
21 | 'form': form,
22 | 'department': department,
23 | 'model': models.Department
24 | })
25 |
26 |
27 | @login_required
28 | def change_salary(request, employee_pk):
29 | employee = get_object_or_404(models.Employee, pk=employee_pk)
30 | form = forms.ChangeSalaryForm(employee=employee, data=request.POST or None)
31 |
32 | if form.is_valid():
33 | form.save()
34 |
35 | salaries = employee.salary_set.all().order_by('from_date')
36 | salary_data = {
37 | 'labels': [salary.from_date.strftime('%Y-%m-%d') for salary in salaries],
38 | 'datasets': [
39 | {'data': [salary.salary for salary in salaries], 'label': ugettext('Salary History')}
40 | ]
41 | }
42 |
43 | return render(request, 'employees/change_salary.html', {
44 | 'form': form,
45 | 'employee': employee,
46 | 'salary_history': json.dumps(salary_data),
47 | 'model': models.Employee
48 | })
49 |
50 |
51 | @login_required
52 | def change_title(request, employee_pk):
53 | employee = get_object_or_404(models.Employee, pk=employee_pk)
54 | form = forms.ChangeTitleForm(employee=employee, data=request.POST or None)
55 |
56 | if form.is_valid():
57 | form.save()
58 |
59 | return render(request, 'employees/change_title.html', {
60 | 'form': form,
61 | 'employee': employee,
62 | 'model': models.Employee
63 | })
64 |
65 |
66 | class DepartmentEmployesListView(ListModelView):
67 | model = models.Employee
68 | list_display = ('emp_no', 'first_name', 'last_name', 'current_salary')
69 | template_name = 'employees/department_employees.html'
70 |
71 | def get_queryset(self):
72 | today = timezone.now().date()
73 | department = get_object_or_404(models.Department, pk=self.kwargs['department_pk'])
74 | queryset = super(DepartmentEmployesListView, self).get_queryset()
75 |
76 | return queryset.filter(
77 | deptemp__department=department,
78 | deptemp__from_date__lte=today,
79 | deptemp__to_date__gt=today
80 | )
81 |
82 | def get_context_data(self, **kwargs):
83 | department = get_object_or_404(models.Department, pk=self.kwargs['department_pk'])
84 | return super(DepartmentEmployesListView, self).get_context_data(
85 | department=department, **kwargs)
86 |
87 |
88 | class EmployeeViewSet(ModelViewSet):
89 | model = models.Employee
90 | list_display = ('emp_no', 'first_name', 'last_name', 'birth_date', 'current_salary')
91 |
92 | change_salary_view = [
93 | r'^(?P.+)/change_salary/$',
94 | change_salary,
95 | '{model_name}_change_salary'
96 | ]
97 |
98 | change_title_view = [
99 | r'^(?P.+)/change_title/$',
100 | change_title,
101 | '{model_name}_change_title'
102 | ]
103 |
104 | def current_salary(self, obj):
105 | salary = obj.salary_set.current()
106 | return salary.salary if salary is not None else 0
107 | current_salary.short_description = _('current salary')
108 |
109 |
110 | class DepartmentViewSet(ModelViewSet):
111 | model = models.Department
112 | list_display = ('dept_no', 'dept_name', 'manager', 'employees')
113 |
114 | change_manager_view = [
115 | r'^(?P.+)/change_manager/$',
116 | change_manager,
117 | '{model_name}_change_manager'
118 | ]
119 |
120 | employees_list_view = [
121 | r'^(?P.+)/employees/$',
122 | DepartmentEmployesListView.as_view(viewset=EmployeeViewSet()),
123 | '{model_name}_employees'
124 | ]
125 |
126 | def manager(self, obj, today=None):
127 | if today is None:
128 | today = timezone.now().date()
129 | manager = obj.deptmanager_set.filter(
130 | from_date__lte=today,
131 | to_date__gt=today
132 | ).first()
133 | return manager.employee if manager is not None else ''
134 |
135 | def employees(self, obj):
136 | return obj.deptemp_set.count()
137 | employees.short_description = _('employees')
138 |
--------------------------------------------------------------------------------
/demo/hr/__init__.py:
--------------------------------------------------------------------------------
1 | default_app_config = 'demo.hr.apps.HrConfig'
--------------------------------------------------------------------------------
/demo/hr/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 |
3 | # Register your models here.
4 | from django.contrib import admin
5 | from .models import *
6 | # Register your models here.
7 | @admin.register(department)
8 | class departmentAdmin(admin.ModelAdmin):
9 | pass
10 |
11 | @admin.register(employee)
12 | class employeeAdmin(admin.ModelAdmin):
13 | pass
--------------------------------------------------------------------------------
/demo/hr/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 | from material.frontend.apps import ModuleMixin
3 | from material.frontend.registry import modules
4 |
5 |
6 | class HrConfig(AppConfig,ModuleMixin):
7 | name = 'demo.hr'
8 | label = 'hr'
9 | verbose_name='资源管理'
10 | icon = 'book '
11 |
--------------------------------------------------------------------------------
/demo/hr/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.11.7 on 2017-11-24 07:47
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 | migrations.swappable_dependency(settings.AUTH_USER_MODEL),
16 | ]
17 |
18 | operations = [
19 | migrations.CreateModel(
20 | name='department',
21 | fields=[
22 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
23 | ('name', models.CharField(max_length=1024, verbose_name='Department Name')),
24 | ('note', models.CharField(max_length=1024, verbose_name='Note')),
25 | ],
26 | options={
27 | 'verbose_name': '部门',
28 | 'verbose_name_plural': '部门',
29 | 'db_table': 'hr.department',
30 | },
31 | ),
32 | migrations.CreateModel(
33 | name='employee',
34 | fields=[
35 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
36 | ('birthday', models.DateTimeField(verbose_name='Date of Birth')),
37 | ('passport_id', models.CharField(max_length=1024, verbose_name='passport No')),
38 | ('sex', models.CharField(choices=[('M', 'Male'), ('F', 'Female'), ('O', 'Other')], max_length=1)),
39 | ('marital', models.CharField(choices=[('single', 'Single'), ('married', 'Married'), ('widower', 'Widower'), ('divorced', 'Divorced')], max_length=10)),
40 | ('address', models.CharField(max_length=1024, verbose_name='Working Address')),
41 | ('work_phone', models.CharField(max_length=1024, verbose_name='Work Phone')),
42 | ('mobile_phone', models.CharField(max_length=1024, verbose_name='Work Mobile')),
43 | ('work_email', models.CharField(max_length=1024, verbose_name='Work Email')),
44 | ('work_location', models.CharField(max_length=1024, verbose_name='Office Location')),
45 | ('notes', models.CharField(max_length=1024, verbose_name='Notes')),
46 | ('Manager', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='lead_member', to='hr.employee')),
47 | ('department', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='member', to='hr.department')),
48 | ('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL, verbose_name='账号绑定')),
49 | ],
50 | options={
51 | 'verbose_name': '雇员',
52 | 'verbose_name_plural': '雇员',
53 | 'db_table': 'hr.employee',
54 | },
55 | ),
56 | migrations.AddField(
57 | model_name='department',
58 | name='leader',
59 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='emp_children', to='hr.employee'),
60 | ),
61 | migrations.AddField(
62 | model_name='department',
63 | name='parent',
64 | field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='dep_children', to='hr.department'),
65 | ),
66 | ]
67 |
--------------------------------------------------------------------------------
/demo/hr/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/hr/migrations/__init__.py
--------------------------------------------------------------------------------
/demo/hr/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from django.contrib.auth.models import User
3 |
4 | # Create your models here.
5 | class employee(models.Model):
6 |
7 | birthday = models.DateTimeField(verbose_name=u"Date of Birth")
8 | passport_id = models.CharField(verbose_name=u'passport No',max_length=1024)
9 | sex = models.CharField(
10 | max_length=1,
11 | choices=(
12 | ("M", "Male"),
13 | ("F", "Female"),
14 | ("O", "Other")))
15 | marital= models.CharField(
16 | max_length=10,
17 | choices=(('single', 'Single'), ('married', 'Married'), ('widower', 'Widower'), ('divorced', 'Divorced')))
18 | department= models.ForeignKey('hr.department',related_name='member')
19 | address=models.CharField(verbose_name=u'Working Address',max_length=1024)
20 | work_phone= models.CharField(verbose_name=u'Work Phone',max_length=1024)
21 | mobile_phone= models.CharField(verbose_name=u'Work Mobile',max_length=1024)
22 | work_email= models.CharField(verbose_name=u'Work Email',max_length=1024)
23 | work_location= models.CharField(verbose_name=u'Office Location',max_length=1024)
24 | notes= models.CharField(verbose_name=u'Notes',max_length=1024)
25 | Manager=models.ForeignKey('hr.employee', blank=True, null=True, related_name='lead_member')
26 |
27 | #
28 | user = models.OneToOneField(User, verbose_name=u"账号绑定")
29 | # image: all image fields are base64 encoded and PIL-supported
30 | #image=models.ImageField(verbose_name=u"Photo")
31 | class Meta:
32 | db_table = 'hr.employee'
33 | verbose_name = '雇员'
34 | verbose_name_plural = "雇员"
35 |
36 | def __str__(self):
37 | return self.user.username
38 |
39 | class department(models.Model):
40 |
41 | class Meta:
42 | db_table = 'hr.department'
43 | verbose_name = '部门'
44 | verbose_name_plural = "部门"
45 |
46 | name = models.CharField(verbose_name=u'Department Name',max_length=1024)
47 | parent = models.ForeignKey('hr.department', blank=True, null=True, related_name='dep_children')
48 | leader = models.ForeignKey('hr.employee', blank=True, null=True, related_name='emp_children')
49 | note=models.CharField(verbose_name=u'Note',max_length=1024)
50 |
51 |
52 | def __str__(self):
53 | # dep_tree = _get_dep_tree(self)
54 | return self.name
55 | #
56 | # def _get_dep_tree(self):
57 | # ret =''
58 | # if (self.parent is not None):
59 | # ret = _get_dep_tree(self.parent)
60 | #
61 | # return ret + '/'+dep.name
62 |
63 |
--------------------------------------------------------------------------------
/demo/hr/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/demo/hr/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url, include
2 | from django.views import generic
3 | from . import views
4 |
5 | urlpatterns = [
6 | url('^$', generic.RedirectView.as_view(url='./employee/', permanent=False), name="index"),
7 | url('^employee/', include(views.EmployeeViewSet().urls)),
8 | url('^department/', include(views.DepartmentViewSet().urls)),
9 | ]
--------------------------------------------------------------------------------
/demo/hr/views.py:
--------------------------------------------------------------------------------
1 | from material.frontend.views import ModelViewSet
2 | from . import models
3 |
4 | class EmployeeViewSet(ModelViewSet):
5 |
6 | model = models.employee
7 |
8 | class DepartmentViewSet(ModelViewSet):
9 |
10 | model = models.department
--------------------------------------------------------------------------------
/demo/integration/__init__.py:
--------------------------------------------------------------------------------
1 | default_app_config = 'demo.integration.apps.IntegrationAppConfig'
2 |
--------------------------------------------------------------------------------
/demo/integration/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 | from material.frontend.apps import ModuleMixin
3 | from django.utils.translation import ugettext_lazy as _
4 |
5 |
6 | class IntegrationAppConfig(ModuleMixin, AppConfig):
7 | name = 'demo.integration'
8 | icon = 'extension '
9 | verbose_name = _("CRUD sample")
10 |
11 | def has_perm(self, user):
12 | return user.is_superuser
13 |
--------------------------------------------------------------------------------
/demo/integration/locale/de/LC_MESSAGES/django.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/integration/locale/de/LC_MESSAGES/django.mo
--------------------------------------------------------------------------------
/demo/integration/locale/de/LC_MESSAGES/django.po:
--------------------------------------------------------------------------------
1 | # distributed under the same license as the Django Material package.
2 | msgid ""
3 | msgstr ""
4 | "Project-Id-Version: django-material\n"
5 | "Report-Msgid-Bugs-To: \n"
6 | "POT-Creation-Date: 2017-05-09 09:52+0000\n"
7 | "Language: de\n"
8 | "MIME-Version: 1.0\n"
9 | "Content-Type: text/plain; charset=UTF-8\n"
10 | "Content-Transfer-Encoding: 8bit\n"
11 | "Plural-Forms: nplurals=2; plural=(n != 1);\n"
12 |
13 | #: admin.py:45
14 | msgid "wiki"
15 | msgstr ""
16 |
17 | #: admin.py:83
18 | msgid "map"
19 | msgstr "karte"
20 |
21 | #: admin.py:87
22 | msgid "short description"
23 | msgstr "kurze beschreibung"
24 |
25 | #: admin.py:109 views.py:69
26 | msgid "sea area"
27 | msgstr "seegebiet"
28 |
29 | #: admin.py:120 views.py:21
30 | msgid "Details"
31 | msgstr ""
32 |
33 | #: admin.py:123 views.py:25
34 | msgid "Fun facts"
35 | msgstr "Fakten"
36 |
37 | #: admin.py:138
38 | msgid "surrounded oceans"
39 | msgstr "umgeben von ozeanen"
40 |
41 | #: admin.py:142
42 | msgid "countries count"
43 | msgstr "länder zählen"
44 |
45 | #: admin.py:182 admin.py:204 views.py:49
46 | msgid "became independent in XX century"
47 | msgstr "Wurde im XX Jahrhundert unabhängig"
48 |
49 | #: apps.py:9
50 | msgid "CRUD sample"
51 | msgstr "CRUD Probe"
52 |
53 | #: models.py:9 models.py:26 models.py:48 models.py:82 models.py:99
54 | msgid "name"
55 | msgstr ""
56 |
57 | #: models.py:10 models.py:30 models.py:49
58 | msgid "area"
59 | msgstr "bereich"
60 |
61 | #: models.py:11
62 | msgid "slug"
63 | msgstr ""
64 |
65 | #: models.py:12
66 | msgid "description"
67 | msgstr "beschreibung"
68 |
69 | #: models.py:13
70 | msgid "map url"
71 | msgstr "karte url"
72 |
73 | #: models.py:16 models.py:28
74 | msgid "ocean"
75 | msgstr "ozean"
76 |
77 | #: models.py:17 models.py:60
78 | msgid "oceans"
79 | msgstr "ozeane"
80 |
81 | #: models.py:27
82 | msgid "parent"
83 | msgstr "elternteil"
84 |
85 | #: models.py:30
86 | msgid "km²"
87 | msgstr ""
88 |
89 | #: models.py:31
90 | msgid "average depth"
91 | msgstr "durchschnittliche tiefe"
92 |
93 | #: models.py:31 models.py:32
94 | msgid "meters"
95 | msgstr "meter"
96 |
97 | #: models.py:32
98 | msgid "maximum depth"
99 | msgstr "maximale tiefe"
100 |
101 | #: models.py:38
102 | msgid "sea"
103 | msgstr "meer"
104 |
105 | #: models.py:39
106 | msgid "seas"
107 | msgstr "meere"
108 |
109 | #: models.py:50 models.py:101
110 | msgid "population"
111 | msgstr "bevölkerung"
112 |
113 | #: models.py:51
114 | msgid "population density"
115 | msgstr "bevölkerungsdichte"
116 |
117 | #: models.py:54
118 | msgid "largest country"
119 | msgstr "größtes land"
120 |
121 | #: models.py:56
122 | msgid "biggest city"
123 | msgstr "größte stadt"
124 |
125 | #: models.py:57
126 | msgid "longest river"
127 | msgstr "längster fluss"
128 |
129 | #: models.py:58
130 | msgid "biggest mountain"
131 | msgstr "größter berg"
132 |
133 | #: models.py:71 models.py:86
134 | msgid "continent"
135 | msgstr "kontinent"
136 |
137 | #: models.py:72
138 | msgid "continents"
139 | msgstr "kontinente"
140 |
141 | #: models.py:81
142 | msgid "code"
143 | msgstr ""
144 |
145 | #: models.py:83
146 | msgid "independence day"
147 | msgstr "tag der unabhängigkeit"
148 |
149 | #: models.py:84
150 | msgid "gay friendly"
151 | msgstr "schwulenfreundlich"
152 |
153 | #: models.py:89 models.py:103
154 | msgid "country"
155 | msgstr "land"
156 |
157 | #: models.py:90
158 | msgid "countries"
159 | msgstr "länder"
160 |
161 | #: models.py:100
162 | msgid "is capital city"
163 | msgstr "Ist Hauptstadt"
164 |
165 | #: models.py:106
166 | msgid "city"
167 | msgstr "stadt"
168 |
169 | #: models.py:107
170 | msgid "cities"
171 | msgstr "städte"
172 |
173 | #: templates/integration/menu.html:3
174 | msgid "Cities"
175 | msgstr "Städte"
176 |
177 | #: templates/integration/menu.html:4
178 | msgid "Continents"
179 | msgstr "Kontinente"
180 |
181 | #: templates/integration/menu.html:5
182 | msgid "Countries"
183 | msgstr "Länder"
184 |
185 | #: templates/integration/menu.html:6
186 | msgid "Oceans"
187 | msgstr "Ozeane"
188 |
189 | #: templates/integration/menu.html:7
190 | msgid "Seas"
191 | msgstr "Meere"
192 |
--------------------------------------------------------------------------------
/demo/integration/locale/es/LC_MESSAGES/django.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/integration/locale/es/LC_MESSAGES/django.mo
--------------------------------------------------------------------------------
/demo/integration/locale/es/LC_MESSAGES/django.po:
--------------------------------------------------------------------------------
1 | # distributed under the same license as the Django Material package.
2 | msgid ""
3 | msgstr ""
4 | "Project-Id-Version: django-material\n"
5 | "Report-Msgid-Bugs-To: \n"
6 | "POT-Creation-Date: 2017-05-09 09:52+0000\n"
7 | "Language: es\n"
8 | "MIME-Version: 1.0\n"
9 | "Content-Type: text/plain; charset=UTF-8\n"
10 | "Content-Transfer-Encoding: 8bit\n"
11 | "Plural-Forms: nplurals=2; plural=(n != 1);\n"
12 |
13 | #: admin.py:45
14 | msgid "wiki"
15 | msgstr ""
16 |
17 | #: admin.py:83
18 | msgid "map"
19 | msgstr "mapa"
20 |
21 | #: admin.py:87
22 | msgid "short description"
23 | msgstr "breve descripción"
24 |
25 | #: admin.py:109 views.py:69
26 | msgid "sea area"
27 | msgstr "ver área"
28 |
29 | #: admin.py:120 views.py:21
30 | msgid "Details"
31 | msgstr "Detalles"
32 |
33 | #: admin.py:123 views.py:25
34 | msgid "Fun facts"
35 | msgstr "Hechos graciosos"
36 |
37 | #: admin.py:138
38 | msgid "surrounded oceans"
39 | msgstr "océanos rodeados"
40 |
41 | #: admin.py:142
42 | msgid "countries count"
43 | msgstr "los países cuentan"
44 |
45 | #: admin.py:182 admin.py:204 views.py:49
46 | msgid "became independent in XX century"
47 | msgstr "Se hizo independiente en el siglo XX"
48 |
49 | #: apps.py:9
50 | msgid "CRUD sample"
51 | msgstr "Muestra CRUD"
52 |
53 | #: models.py:9 models.py:26 models.py:48 models.py:82 models.py:99
54 | msgid "name"
55 | msgstr "nombre"
56 |
57 | #: models.py:10 models.py:30 models.py:49
58 | msgid "area"
59 | msgstr "zona"
60 |
61 | #: models.py:11
62 | msgid "slug"
63 | msgstr ""
64 |
65 | #: models.py:12
66 | msgid "description"
67 | msgstr "descripción"
68 |
69 | #: models.py:13
70 | msgid "map url"
71 | msgstr "URL del mapa"
72 |
73 | #: models.py:16 models.py:28
74 | msgid "ocean"
75 | msgstr "oceano"
76 |
77 | #: models.py:17 models.py:60
78 | msgid "oceans"
79 | msgstr "océanos"
80 |
81 | #: models.py:27
82 | msgid "parent"
83 | msgstr "cause"
84 |
85 | #: models.py:30
86 | msgid "km²"
87 | msgstr ""
88 |
89 | #: models.py:31
90 | msgid "average depth"
91 | msgstr "profundidad promedio"
92 |
93 | #: models.py:31 models.py:32
94 | msgid "meters"
95 | msgstr "metros"
96 |
97 | #: models.py:32
98 | msgid "maximum depth"
99 | msgstr "profundidad máxima"
100 |
101 | #: models.py:38
102 | msgid "sea"
103 | msgstr "mar"
104 |
105 | #: models.py:39
106 | msgid "seas"
107 | msgstr "mares"
108 |
109 | #: models.py:50 models.py:101
110 | msgid "population"
111 | msgstr "población"
112 |
113 | #: models.py:51
114 | msgid "population density"
115 | msgstr "densidad de población"
116 |
117 | #: models.py:54
118 | msgid "largest country"
119 | msgstr "el país más grande"
120 |
121 | #: models.py:56
122 | msgid "biggest city"
123 | msgstr "la ciudad más grande"
124 |
125 | #: models.py:57
126 | msgid "longest river"
127 | msgstr "rio más largo"
128 |
129 | #: models.py:58
130 | msgid "biggest mountain"
131 | msgstr "montaña mas grande"
132 |
133 | #: models.py:71 models.py:86
134 | msgid "continent"
135 | msgstr "continente"
136 |
137 | #: models.py:72
138 | msgid "continents"
139 | msgstr "continentes"
140 |
141 | #: models.py:81
142 | msgid "code"
143 | msgstr "código"
144 |
145 | #: models.py:83
146 | msgid "independence day"
147 | msgstr "día de la Independencia"
148 |
149 | #: models.py:84
150 | msgid "gay friendly"
151 | msgstr "amistoso"
152 |
153 | #: models.py:89 models.py:103
154 | msgid "country"
155 | msgstr "país"
156 |
157 | #: models.py:90
158 | msgid "countries"
159 | msgstr "países"
160 |
161 | #: models.py:100
162 | msgid "is capital city"
163 | msgstr "Es la ciudad capital"
164 |
165 | #: models.py:106
166 | msgid "city"
167 | msgstr "ciudad"
168 |
169 | #: models.py:107
170 | msgid "cities"
171 | msgstr "ciudades"
172 |
173 | #: templates/integration/menu.html:3
174 | msgid "Cities"
175 | msgstr "Ciudades"
176 |
177 | #: templates/integration/menu.html:4
178 | msgid "Continents"
179 | msgstr "Continentes"
180 |
181 | #: templates/integration/menu.html:5
182 | msgid "Countries"
183 | msgstr "Países"
184 |
185 | #: templates/integration/menu.html:6
186 | msgid "Oceans"
187 | msgstr "Océanos"
188 |
189 | #: templates/integration/menu.html:7
190 | msgid "Seas"
191 | msgstr "Mares"
192 |
--------------------------------------------------------------------------------
/demo/integration/locale/fr/LC_MESSAGES/django.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/integration/locale/fr/LC_MESSAGES/django.mo
--------------------------------------------------------------------------------
/demo/integration/locale/fr/LC_MESSAGES/django.po:
--------------------------------------------------------------------------------
1 | # distributed under the same license as the Django Material package.
2 | msgid ""
3 | msgstr ""
4 | "Project-Id-Version: django-material\n"
5 | "Report-Msgid-Bugs-To: \n"
6 | "POT-Creation-Date: 2017-05-09 09:52+0000\n"
7 | "Language: fr\n"
8 | "MIME-Version: 1.0\n"
9 | "Content-Type: text/plain; charset=UTF-8\n"
10 | "Content-Transfer-Encoding: 8bit\n"
11 | "Plural-Forms: nplurals=2; plural=(n > 1);\n"
12 |
13 | #: admin.py:45
14 | msgid "wiki"
15 | msgstr ""
16 |
17 | #: admin.py:83
18 | msgid "map"
19 | msgstr "carte"
20 |
21 | #: admin.py:87
22 | msgid "short description"
23 | msgstr "brève description"
24 |
25 | #: admin.py:109 views.py:69
26 | msgid "sea area"
27 | msgstr "zone maritime"
28 |
29 | #: admin.py:120 views.py:21
30 | msgid "Details"
31 | msgstr "Détails"
32 |
33 | #: admin.py:123 views.py:25
34 | msgid "Fun facts"
35 | msgstr "Faits amusants"
36 |
37 | #: admin.py:138
38 | msgid "surrounded oceans"
39 | msgstr "océans entourés"
40 |
41 | #: admin.py:142
42 | msgid "countries count"
43 | msgstr "pays comptent"
44 |
45 | #: admin.py:182 admin.py:204 views.py:49
46 | msgid "became independent in XX century"
47 | msgstr "est devenu indépendant au XXème siècle"
48 |
49 | #: apps.py:9
50 | msgid "CRUD sample"
51 | msgstr "Échantillon CRUD"
52 |
53 | #: models.py:9 models.py:26 models.py:48 models.py:82 models.py:99
54 | msgid "name"
55 | msgstr "prénom"
56 |
57 | #: models.py:10 models.py:30 models.py:49
58 | msgid "area"
59 | msgstr "région"
60 |
61 | #: models.py:11
62 | msgid "slug"
63 | msgstr ""
64 |
65 | #: models.py:12
66 | msgid "description"
67 | msgstr "la description"
68 |
69 | #: models.py:13
70 | msgid "map url"
71 | msgstr "URL de la carte"
72 |
73 | #: models.py:16 models.py:28
74 | msgid "ocean"
75 | msgstr "océan"
76 |
77 | #: models.py:17 models.py:60
78 | msgid "oceans"
79 | msgstr "océans"
80 |
81 | #: models.py:27
82 | msgid "parent"
83 | msgstr "origine"
84 |
85 | #: models.py:30
86 | msgid "km²"
87 | msgstr ""
88 |
89 | #: models.py:31
90 | msgid "average depth"
91 | msgstr "profondeur moyenne"
92 |
93 | #: models.py:31 models.py:32
94 | msgid "meters"
95 | msgstr "metros"
96 |
97 | #: models.py:32
98 | msgid "maximum depth"
99 | msgstr "profondeur maximale"
100 |
101 | #: models.py:38
102 | msgid "sea"
103 | msgstr "mer"
104 |
105 | #: models.py:39
106 | msgid "seas"
107 | msgstr "Les mers"
108 |
109 | #: models.py:50 models.py:101
110 | msgid "population"
111 | msgstr "population"
112 |
113 | #: models.py:51
114 | msgid "population density"
115 | msgstr "densité de population"
116 |
117 | #: models.py:54
118 | msgid "largest country"
119 | msgstr "le plus grand pays"
120 |
121 | #: models.py:56
122 | msgid "biggest city"
123 | msgstr "la plus grande ville"
124 |
125 | #: models.py:57
126 | msgid "longest river"
127 | msgstr "la plus longue rivière"
128 |
129 | #: models.py:58
130 | msgid "biggest mountain"
131 | msgstr "la plus grande montagne"
132 |
133 | #: models.py:71 models.py:86
134 | msgid "continent"
135 | msgstr "continent"
136 |
137 | #: models.py:72
138 | msgid "continents"
139 | msgstr "continents"
140 |
141 | #: models.py:81
142 | msgid "code"
143 | msgstr "code"
144 |
145 | #: models.py:83
146 | msgid "independence day"
147 | msgstr "le jour de l'indépendance"
148 |
149 | #: models.py:84
150 | msgid "gay friendly"
151 | msgstr "amical"
152 |
153 | #: models.py:89 models.py:103
154 | msgid "country"
155 | msgstr "pays"
156 |
157 | #: models.py:90
158 | msgid "countries"
159 | msgstr "des pays"
160 |
161 | #: models.py:100
162 | msgid "is capital city"
163 | msgstr "Est la capitale"
164 |
165 | #: models.py:106
166 | msgid "city"
167 | msgstr "ville"
168 |
169 | #: models.py:107
170 | msgid "cities"
171 | msgstr "villes"
172 |
173 | #: templates/integration/menu.html:3
174 | msgid "Cities"
175 | msgstr "Villes"
176 |
177 | #: templates/integration/menu.html:4
178 | msgid "Continents"
179 | msgstr "Continents"
180 |
181 | #: templates/integration/menu.html:5
182 | msgid "Countries"
183 | msgstr "Des pays"
184 |
185 | #: templates/integration/menu.html:6
186 | msgid "Oceans"
187 | msgstr "Océans"
188 |
189 | #: templates/integration/menu.html:7
190 | msgid "Seas"
191 | msgstr "Les mers"
192 |
--------------------------------------------------------------------------------
/demo/integration/locale/ko/LC_MESSAGES/django.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/integration/locale/ko/LC_MESSAGES/django.mo
--------------------------------------------------------------------------------
/demo/integration/locale/ko/LC_MESSAGES/django.po:
--------------------------------------------------------------------------------
1 | # distributed under the same license as the Django Material package.
2 | msgid ""
3 | msgstr ""
4 | "Project-Id-Version: django-material\n"
5 | "Report-Msgid-Bugs-To: \n"
6 | "POT-Creation-Date: 2017-05-09 09:52+0000\n"
7 | "Language: ko\n"
8 | "MIME-Version: 1.0\n"
9 | "Content-Type: text/plain; charset=UTF-8\n"
10 | "Content-Transfer-Encoding: 8bit\n"
11 | "Plural-Forms: nplurals=1; plural=0;\n"
12 |
13 | #: admin.py:45
14 | msgid "wiki"
15 | msgstr "위키"
16 |
17 | #: admin.py:83
18 | msgid "map"
19 | msgstr "지도"
20 |
21 | #: admin.py:87
22 | msgid "short description"
23 | msgstr "간단한 설명"
24 |
25 | #: admin.py:109 views.py:69
26 | msgid "sea area"
27 | msgstr "해역"
28 |
29 | #: admin.py:120 views.py:21
30 | msgid "Details"
31 | msgstr "세부"
32 |
33 | #: admin.py:123 views.py:25
34 | msgid "Fun facts"
35 | msgstr "재미있는 사실"
36 |
37 | #: admin.py:138
38 | msgid "surrounded oceans"
39 | msgstr "둘러싸인 바다"
40 |
41 | #: admin.py:142
42 | msgid "countries count"
43 | msgstr "국가 수"
44 |
45 | #: admin.py:182 admin.py:204 views.py:49
46 | msgid "became independent in XX century"
47 | msgstr "20 세기에 독립했다."
48 |
49 | #: apps.py:9
50 | msgid "CRUD sample"
51 | msgstr "CRUD 샘플"
52 |
53 | #: models.py:9 models.py:26 models.py:48 models.py:82 models.py:99
54 | msgid "name"
55 | msgstr "이름"
56 |
57 | #: models.py:10 models.py:30 models.py:49
58 | msgid "area"
59 | msgstr "지역"
60 |
61 | #: models.py:11
62 | msgid "slug"
63 | msgstr "URL 슬러그"
64 |
65 | #: models.py:12
66 | msgid "description"
67 | msgstr "기술"
68 |
69 | #: models.py:13
70 | msgid "map url"
71 | msgstr "지도 URL"
72 |
73 | #: models.py:16 models.py:28
74 | msgid "ocean"
75 | msgstr "대양"
76 |
77 | #: models.py:17 models.py:60
78 | msgid "oceans"
79 | msgstr "대양"
80 |
81 | #: models.py:27
82 | msgid "parent"
83 | msgstr "유래"
84 |
85 | #: models.py:30
86 | msgid "km²"
87 | msgstr ""
88 |
89 | #: models.py:31
90 | msgid "average depth"
91 | msgstr "평균 깊이"
92 |
93 | #: models.py:31 models.py:32
94 | msgid "meters"
95 | msgstr "미터"
96 |
97 | #: models.py:32
98 | msgid "maximum depth"
99 | msgstr "최대 깊이"
100 |
101 | #: models.py:38
102 | msgid "sea"
103 | msgstr "바다"
104 |
105 | #: models.py:39
106 | msgid "seas"
107 | msgstr "바다"
108 |
109 | #: models.py:50 models.py:101
110 | msgid "population"
111 | msgstr "인구"
112 |
113 | #: models.py:51
114 | msgid "population density"
115 | msgstr "인구 밀도"
116 |
117 | #: models.py:54
118 | msgid "largest country"
119 | msgstr "가장 큰 나라"
120 |
121 | #: models.py:56
122 | msgid "biggest city"
123 | msgstr "가장 큰 도시"
124 |
125 | #: models.py:57
126 | msgid "longest river"
127 | msgstr "가장 긴 강"
128 |
129 | #: models.py:58
130 | msgid "biggest mountain"
131 | msgstr "가장 큰 산"
132 |
133 | #: models.py:71 models.py:86
134 | msgid "continent"
135 | msgstr "대륙"
136 |
137 | #: models.py:72
138 | msgid "continents"
139 | msgstr "대륙"
140 |
141 | #: models.py:81
142 | msgid "code"
143 | msgstr "규약"
144 |
145 | #: models.py:83
146 | msgid "independence day"
147 | msgstr "독립 기념일"
148 |
149 | #: models.py:84
150 | msgid "gay friendly"
151 | msgstr "동성애자 친화적 인"
152 |
153 | #: models.py:89 models.py:103
154 | msgid "country"
155 | msgstr "국가"
156 |
157 | #: models.py:90
158 | msgid "countries"
159 | msgstr "국가"
160 |
161 | #: models.py:100
162 | msgid "is capital city"
163 | msgstr "수도이다"
164 |
165 | #: models.py:106
166 | msgid "city"
167 | msgstr "시티"
168 |
169 | #: models.py:107
170 | msgid "cities"
171 | msgstr "도시들"
172 |
173 | #: templates/integration/menu.html:3
174 | msgid "Cities"
175 | msgstr "도시들"
176 |
177 | #: templates/integration/menu.html:4
178 | msgid "Continents"
179 | msgstr "대륙"
180 |
181 | #: templates/integration/menu.html:5
182 | msgid "Countries"
183 | msgstr "국가"
184 |
185 | #: templates/integration/menu.html:6
186 | msgid "Oceans"
187 | msgstr "대양"
188 |
189 | #: templates/integration/menu.html:7
190 | msgid "Seas"
191 | msgstr "바다"
192 |
--------------------------------------------------------------------------------
/demo/integration/locale/ru/LC_MESSAGES/django.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/integration/locale/ru/LC_MESSAGES/django.mo
--------------------------------------------------------------------------------
/demo/integration/locale/ru/LC_MESSAGES/django.po:
--------------------------------------------------------------------------------
1 | # distributed under the same license as the Django Material package.
2 | msgid ""
3 | msgstr ""
4 | "Project-Id-Version: django-material\n"
5 | "MIME-Version: 1.0\n"
6 | "Content-Type: text/plain; charset=UTF-8\n"
7 | "Content-Transfer-Encoding: 8bit\n"
8 | "Language: ru\n"
9 | "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n"
10 | "%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n"
11 | "%100>=11 && n%100<=14)? 2 : 3);\n"
12 |
13 | #: admin.py:45
14 | msgid "wiki"
15 | msgstr "вики"
16 |
17 | #: admin.py:83
18 | msgid "map"
19 | msgstr "карта"
20 |
21 | #: admin.py:87
22 | msgid "short description"
23 | msgstr "описание"
24 |
25 | #: admin.py:109 views.py:68
26 | msgid "sea area"
27 | msgstr "площадь моря"
28 |
29 | #: admin.py:120 views.py:21
30 | msgid "Details"
31 | msgstr "Подробности"
32 |
33 | #: admin.py:123 views.py:25
34 | msgid "Fun facts"
35 | msgstr "Забавные факты"
36 |
37 | #: admin.py:138
38 | msgid "surrounded oceans"
39 | msgstr "окружающие океаны"
40 |
41 | #: admin.py:142
42 | msgid "countries count"
43 | msgstr "количество стран"
44 |
45 | #: admin.py:182 admin.py:204
46 | msgid "became independent in XX century"
47 | msgstr "Обрела независимость в XX веке"
48 |
49 | #: apps.py:9
50 | msgid "CRUD sample"
51 | msgstr "CRUD пример"
52 |
53 | #: models.py:9 models.py:26 models.py:48 models.py:82 models.py:99
54 | msgid "name"
55 | msgstr "название"
56 |
57 | #: models.py:10 models.py:30 models.py:49
58 | msgid "area"
59 | msgstr "площадь"
60 |
61 | #: models.py:11
62 | msgid "slug"
63 | msgstr ""
64 |
65 | #: models.py:12
66 | msgid "description"
67 | msgstr "описание"
68 |
69 | #: models.py:13
70 | msgid "map url"
71 | msgstr "URL-адрес карты"
72 |
73 | #: models.py:16 models.py:28
74 | msgid "ocean"
75 | msgstr "океан"
76 |
77 | #: models.py:17 models.py:60
78 | msgid "oceans"
79 | msgstr "океаны"
80 |
81 | #: models.py:27
82 | msgid "parent"
83 | msgstr "родитель"
84 |
85 | #: models.py:30
86 | msgid "km²"
87 | msgstr "км²"
88 |
89 | #: models.py:31
90 | msgid "average depth"
91 | msgstr "средняя глубина"
92 |
93 | #: models.py:31 models.py:32
94 | msgid "meters"
95 | msgstr "метры"
96 |
97 | #: models.py:32
98 | msgid "maximum depth"
99 | msgstr "максимальная глубина"
100 |
101 | #: models.py:38
102 | msgid "sea"
103 | msgstr "море"
104 |
105 | #: models.py:39
106 | msgid "seas"
107 | msgstr "моря"
108 |
109 | #: models.py:50 models.py:101
110 | msgid "population"
111 | msgstr "население"
112 |
113 | #: models.py:51
114 | msgid "population density"
115 | msgstr "плотность населения"
116 |
117 | #: models.py:54
118 | msgid "largest country"
119 | msgstr "самая большая страна"
120 |
121 | #: models.py:56
122 | msgid "biggest city"
123 | msgstr "самый большой город"
124 |
125 | #: models.py:57
126 | msgid "longest river"
127 | msgstr "самая длинная река"
128 |
129 | #: models.py:58
130 | msgid "biggest mountain"
131 | msgstr "самая большая гора"
132 |
133 | #: models.py:71 models.py:86
134 | msgid "continent"
135 | msgstr "континент"
136 |
137 | #: models.py:72
138 | msgid "continents"
139 | msgstr "континенты"
140 |
141 | #: models.py:81
142 | msgid "code"
143 | msgstr "код"
144 |
145 | #: models.py:83
146 | msgid "independence day"
147 | msgstr "день независимости"
148 |
149 | #: models.py:84
150 | msgid "gay friendly"
151 | msgstr "дружелюбная"
152 |
153 | #: models.py:89 models.py:103
154 | msgid "country"
155 | msgstr "страна"
156 |
157 | #: models.py:90
158 | msgid "countries"
159 | msgstr "страны"
160 |
161 | #: models.py:100
162 | msgid "is capital city"
163 | msgstr "столица"
164 |
165 | #: models.py:106
166 | msgid "city"
167 | msgstr "город"
168 |
169 | #: models.py:107
170 | msgid "cities"
171 | msgstr "города"
172 |
173 | #: templates/integration/menu.html:3
174 | msgid "Cities"
175 | msgstr "Города"
176 |
177 | #: templates/integration/menu.html:4
178 | msgid "Continents"
179 | msgstr "Континенты"
180 |
181 | #: templates/integration/menu.html:5
182 | msgid "Countries"
183 | msgstr "Страны"
184 |
185 | #: templates/integration/menu.html:6
186 | msgid "Oceans"
187 | msgstr "Океаны"
188 |
189 | #: templates/integration/menu.html:7
190 | msgid "Seas"
191 | msgstr "Моря"
192 |
--------------------------------------------------------------------------------
/demo/integration/locale/zh_Hans/LC_MESSAGES/django.mo:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/integration/locale/zh_Hans/LC_MESSAGES/django.mo
--------------------------------------------------------------------------------
/demo/integration/locale/zh_Hans/LC_MESSAGES/django.po:
--------------------------------------------------------------------------------
1 | # distributed under the same license as the Django Material package.
2 | msgid ""
3 | msgstr ""
4 | "Project-Id-Version: django-material\n"
5 | "Report-Msgid-Bugs-To: \n"
6 | "POT-Creation-Date: 2017-05-09 09:52+0000\n"
7 | "Language: zh_CN\n"
8 | "MIME-Version: 1.0\n"
9 | "Content-Type: text/plain; charset=UTF-8\n"
10 | "Content-Transfer-Encoding: 8bit\n"
11 | "Plural-Forms: nplurals=1; plural=0;\n"
12 |
13 | #: admin.py:45
14 | msgid "wiki"
15 | msgstr "维基"
16 |
17 | #: admin.py:83
18 | msgid "map"
19 | msgstr "地图"
20 |
21 | #: admin.py:87
22 | msgid "short description"
23 | msgstr "简短的介绍"
24 |
25 | #: admin.py:109 views.py:69
26 | msgid "sea area"
27 | msgstr "海域"
28 |
29 | #: admin.py:120 views.py:21
30 | msgid "Details"
31 | msgstr "细节"
32 |
33 | #: admin.py:123 views.py:25
34 | msgid "Fun facts"
35 | msgstr "有趣的事实"
36 |
37 | #: admin.py:138
38 | msgid "surrounded oceans"
39 | msgstr "周围的海洋"
40 |
41 | #: admin.py:142
42 | msgid "countries count"
43 | msgstr "国家数"
44 |
45 | #: admin.py:182 admin.py:204 views.py:49
46 | msgid "became independent in XX century"
47 | msgstr "在二十世纪成为独立的"
48 |
49 | #: apps.py:9
50 | msgid "CRUD sample"
51 | msgstr "CRUD样本"
52 |
53 | #: models.py:9 models.py:26 models.py:48 models.py:82 models.py:99
54 | msgid "name"
55 | msgstr "名称"
56 |
57 | #: models.py:10 models.py:30 models.py:49
58 | msgid "area"
59 | msgstr "区"
60 |
61 | #: models.py:11
62 | msgid "slug"
63 | msgstr ""
64 |
65 | #: models.py:12
66 | msgid "description"
67 | msgstr "描述"
68 |
69 | #: models.py:13
70 | msgid "map url"
71 | msgstr "地图网址"
72 |
73 | #: models.py:16 models.py:28
74 | msgid "ocean"
75 | msgstr "海洋"
76 |
77 | #: models.py:17 models.py:60
78 | msgid "oceans"
79 | msgstr "海洋"
80 |
81 | #: models.py:27
82 | msgid "parent"
83 | msgstr "起源"
84 |
85 | #: models.py:30
86 | msgid "km²"
87 | msgstr "平方公里"
88 |
89 | #: models.py:31
90 | msgid "average depth"
91 | msgstr "平均深度"
92 |
93 | #: models.py:31 models.py:32
94 | msgid "meters"
95 | msgstr "米"
96 |
97 | #: models.py:32
98 | msgid "maximum depth"
99 | msgstr "最大深度"
100 |
101 | #: models.py:38
102 | msgid "sea"
103 | msgstr "海"
104 |
105 | #: models.py:39
106 | msgid "seas"
107 | msgstr "海域"
108 |
109 | #: models.py:50 models.py:101
110 | msgid "population"
111 | msgstr "人口"
112 |
113 | #: models.py:51
114 | msgid "population density"
115 | msgstr "人口密度"
116 |
117 | #: models.py:54
118 | msgid "largest country"
119 | msgstr "最大的国家"
120 |
121 | #: models.py:56
122 | msgid "biggest city"
123 | msgstr "最大的城市"
124 |
125 | #: models.py:57
126 | msgid "longest river"
127 | msgstr "最长的河"
128 |
129 | #: models.py:58
130 | msgid "biggest mountain"
131 | msgstr "最大的山"
132 |
133 | #: models.py:71 models.py:86
134 | msgid "continent"
135 | msgstr "大陆"
136 |
137 | #: models.py:72
138 | msgid "continents"
139 | msgstr "大陆"
140 |
141 | #: models.py:81
142 | msgid "code"
143 | msgstr "码"
144 |
145 | #: models.py:83
146 | msgid "independence day"
147 | msgstr "独立日"
148 |
149 | #: models.py:84
150 | msgid "gay friendly"
151 | msgstr "同志友好"
152 |
153 | #: models.py:89 models.py:103
154 | msgid "country"
155 | msgstr "国家"
156 |
157 | #: models.py:90
158 | msgid "countries"
159 | msgstr "国家"
160 |
161 | #: models.py:100
162 | msgid "is capital city"
163 | msgstr "是首都"
164 |
165 | #: models.py:106
166 | msgid "city"
167 | msgstr "市"
168 |
169 | #: models.py:107
170 | msgid "cities"
171 | msgstr "城市"
172 |
173 | #: templates/integration/menu.html:3
174 | msgid "Cities"
175 | msgstr "城市"
176 |
177 | #: templates/integration/menu.html:4
178 | msgid "Continents"
179 | msgstr "大陆"
180 |
181 | #: templates/integration/menu.html:5
182 | msgid "Countries"
183 | msgstr "国家"
184 |
185 | #: templates/integration/menu.html:6
186 | msgid "Oceans"
187 | msgstr "海洋"
188 |
189 | #: templates/integration/menu.html:7
190 | msgid "Seas"
191 | msgstr "海域"
192 |
--------------------------------------------------------------------------------
/demo/integration/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from __future__ import unicode_literals
3 |
4 | from django.db import migrations, models
5 |
6 |
7 | class Migration(migrations.Migration):
8 |
9 | dependencies = [
10 | ]
11 |
12 | operations = [
13 | migrations.CreateModel(
14 | name='City',
15 | fields=[
16 | ('id', models.AutoField(primary_key=True, auto_created=True, serialize=False, verbose_name='ID')),
17 | ('name', models.CharField(max_length=250)),
18 | ('is_capital', models.BooleanField(default=False)),
19 | ('population', models.BigIntegerField()),
20 | ],
21 | options={
22 | 'ordering': ['name'],
23 | 'verbose_name_plural': 'cities',
24 | },
25 | ),
26 | migrations.CreateModel(
27 | name='Continent',
28 | fields=[
29 | ('name', models.CharField(primary_key=True, serialize=False, max_length=250)),
30 | ('area', models.BigIntegerField(help_text='km²')),
31 | ('population', models.BigIntegerField()),
32 | ('population_density', models.DecimalField(decimal_places=2, max_digits=8)),
33 | ('longest_river', models.CharField(max_length=250, blank=True, null=True)),
34 | ('biggest_mountain', models.CharField(max_length=250, blank=True, null=True)),
35 | ('hemisphere', models.CharField(max_length=5, choices=[('NORTH', 'North'), ('SOUTH', 'South'), ('BOTH', 'Both')])),
36 | ('biggest_city', models.OneToOneField(on_delete=models.CASCADE, blank=True, null=True, to='integration.City')),
37 | ],
38 | options={
39 | 'ordering': ['name'],
40 | },
41 | ),
42 | migrations.CreateModel(
43 | name='Country',
44 | fields=[
45 | ('id', models.AutoField(primary_key=True, auto_created=True, serialize=False, verbose_name='ID')),
46 | ('code', models.CharField(max_length=3, unique=True)),
47 | ('name', models.CharField(max_length=250)),
48 | ('independence_day', models.DateField(blank=True, null=True)),
49 | ('gay_friendly', models.NullBooleanField()),
50 | ('continent', models.ForeignKey(to='integration.Continent', on_delete=models.CASCADE, related_name='countries', null=True)),
51 | ],
52 | options={
53 | 'ordering': ['name'],
54 | 'verbose_name_plural': 'countries',
55 | },
56 | ),
57 | migrations.CreateModel(
58 | name='Ocean',
59 | fields=[
60 | ('name', models.CharField(primary_key=True, serialize=False, max_length=250)),
61 | ('area', models.BigIntegerField()),
62 | ('slug', models.SlugField()),
63 | ('description', models.TextField()),
64 | ('map_url', models.URLField()),
65 | ],
66 | options={
67 | 'ordering': ['name'],
68 | },
69 | ),
70 | migrations.CreateModel(
71 | name='Sea',
72 | fields=[
73 | ('id', models.AutoField(primary_key=True, auto_created=True, serialize=False, verbose_name='ID')),
74 | ('name', models.CharField(max_length=250)),
75 | ('area', models.BigIntegerField(help_text='km²')),
76 | ('avg_depth', models.IntegerField(help_text='meters', blank=True, null=True)),
77 | ('max_depth', models.IntegerField(help_text='meters', blank=True, null=True)),
78 | ('basin_countries', models.ManyToManyField(to='integration.Country', blank=True, related_name='seas')),
79 | ('ocean', models.ForeignKey(to='integration.Ocean', on_delete=models.CASCADE)),
80 | ('parent', models.ForeignKey(on_delete=models.CASCADE, blank=True, null=True, to='integration.Sea')),
81 | ],
82 | options={
83 | 'ordering': ['name'],
84 | },
85 | ),
86 | migrations.AddField(
87 | model_name='continent',
88 | name='largest_country',
89 | field=models.OneToOneField(to='integration.Country', on_delete=models.CASCADE, blank=True, null=True, related_name='+'),
90 | ),
91 | migrations.AddField(
92 | model_name='continent',
93 | name='oceans',
94 | field=models.ManyToManyField(to='integration.Ocean'),
95 | ),
96 | migrations.AddField(
97 | model_name='city',
98 | name='country',
99 | field=models.ForeignKey(to='integration.Country', on_delete=models.CASCADE, related_name='cities'),
100 | ),
101 | migrations.AlterUniqueTogether(
102 | name='city',
103 | unique_together=set([('name', 'country')]),
104 | ),
105 | ]
106 |
--------------------------------------------------------------------------------
/demo/integration/migrations/0003_auto_20171128_1814.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.11.7 on 2017-11-28 10:14
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('integration', '0002_i18n'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterField(
16 | model_name='sea',
17 | name='area',
18 | field=models.BigIntegerField(help_text='平方公里', verbose_name='area'),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/demo/integration/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/integration/migrations/__init__.py
--------------------------------------------------------------------------------
/demo/integration/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from django.utils.encoding import python_2_unicode_compatible
3 | from django.utils.safestring import mark_safe
4 | from django.utils.translation import ugettext_lazy as _
5 |
6 |
7 | @python_2_unicode_compatible
8 | class Ocean(models.Model):
9 | name = models.CharField(_('name'), max_length=250, primary_key=True)
10 | area = models.BigIntegerField(_('area'))
11 | slug = models.SlugField(_('slug'))
12 | description = models.TextField(_('description'))
13 | map_url = models.URLField(_('map url'))
14 |
15 | class Meta:
16 | verbose_name = _('ocean')
17 | verbose_name_plural = _('oceans')
18 | ordering = ['name']
19 |
20 | def __str__(self):
21 | return self.name if self.name is not None else 'Ocean'
22 |
23 |
24 | @python_2_unicode_compatible
25 | class Sea(models.Model):
26 | name = models.CharField(_('name'), max_length=250)
27 | parent = models.ForeignKey('self', on_delete=models.CASCADE, blank=True, null=True, verbose_name=_('parent'))
28 | ocean = models.ForeignKey(Ocean, on_delete=models.CASCADE, verbose_name=_('ocean'))
29 |
30 | area = models.BigIntegerField(_('area'), help_text=mark_safe(_('km²')))
31 | avg_depth = models.IntegerField(_('average depth'), help_text=_('meters'), null=True, blank=True)
32 | max_depth = models.IntegerField(_('maximum depth'), help_text=_('meters'), null=True, blank=True)
33 |
34 | basin_countries = models.ManyToManyField(
35 | 'Country', related_name='seas', blank=True)
36 |
37 | def get_parent_id_display(self):
38 | return self.parent
39 |
40 | class Meta:
41 | verbose_name = _('sea')
42 | verbose_name_plural = _('seas')
43 | ordering = ['name']
44 |
45 | def __str__(self):
46 | return self.name
47 |
48 |
49 | @python_2_unicode_compatible
50 | class Continent(models.Model):
51 | name = models.CharField(_('name'), max_length=250, primary_key=True)
52 | area = models.BigIntegerField(_('area'), help_text=mark_safe('km²'))
53 | population = models.BigIntegerField(_('population'))
54 | population_density = models.DecimalField(_('population density'), decimal_places=2, max_digits=8)
55 |
56 | largest_country = models.OneToOneField(
57 | 'Country', on_delete=models.CASCADE, related_name='+', blank=True, null=True, verbose_name=_('largest country'))
58 | biggest_city = models.OneToOneField(
59 | 'City', on_delete=models.CASCADE, blank=True, null=True, verbose_name=_('biggest city'))
60 | longest_river = models.CharField(_('longest river'), max_length=250, blank=True, null=True)
61 | biggest_mountain = models.CharField(_('biggest mountain'), max_length=250, blank=True, null=True)
62 |
63 | oceans = models.ManyToManyField(Ocean, verbose_name=_('oceans'))
64 | hemisphere = models.CharField(
65 | max_length=5, choices=(
66 | ('NORTH', 'North'),
67 | ('SOUTH', 'South'),
68 | ('BOTH', 'Both')))
69 |
70 | def __str__(self):
71 | return self.name if self.name is not None else 'Continent'
72 |
73 | class Meta:
74 | verbose_name = _('continent')
75 | verbose_name_plural = _('continents')
76 | ordering = ['name']
77 |
78 | def countries_count(self):
79 | return self.countries.count()
80 | countries_count.short_description = _('countries count')
81 |
82 |
83 | @python_2_unicode_compatible
84 | class Country(models.Model):
85 | code = models.CharField(_('code'), max_length=3, unique=True)
86 | name = models.CharField(_('name'), max_length=250)
87 | independence_day = models.DateField(_('independence day'), null=True, blank=True)
88 | gay_friendly = models.NullBooleanField(_('gay friendly'))
89 | continent = models.ForeignKey(
90 | Continent, on_delete=models.CASCADE, null=True, related_name='countries', verbose_name=_('continent'))
91 |
92 | class Meta:
93 | verbose_name = _('country')
94 | verbose_name_plural = _('countries')
95 | ordering = ['name']
96 |
97 | def __str__(self):
98 | return self.name
99 |
100 |
101 | @python_2_unicode_compatible
102 | class City(models.Model):
103 | name = models.CharField(_('name'), max_length=250)
104 | is_capital = models.BooleanField(_('is capital city'), default=False)
105 | population = models.BigIntegerField(_('population'))
106 | country = models.ForeignKey(
107 | Country, on_delete=models.CASCADE, related_name='cities', verbose_name=_('country'))
108 |
109 | class Meta:
110 | verbose_name = _('city')
111 | verbose_name_plural = _('cities')
112 | unique_together = ('name', 'country')
113 | ordering = ['name']
114 |
115 | def __str__(self):
116 | return self.name
117 |
--------------------------------------------------------------------------------
/demo/integration/templates/integration/base_module.html:
--------------------------------------------------------------------------------
1 | {% extends 'material/frontend/base_module.html' %}
2 |
3 | {% block extrahead %}
4 |
5 | {% endblock %}
6 |
--------------------------------------------------------------------------------
/demo/integration/templates/integration/menu.html:
--------------------------------------------------------------------------------
1 | {% load i18n %}
2 |
9 |
--------------------------------------------------------------------------------
/demo/integration/urls.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url, include
2 | from django.views import generic
3 |
4 | from . import views
5 |
6 | urlpatterns = [
7 | url('^$', generic.RedirectView.as_view(url='./city/'), name="index"),
8 | url('^city/', include(views.CityViewSet().urls)),
9 | url('^continent/', include(views.ContinentViewSet().urls)),
10 | url('^country/', include(views.CountryViewSet().urls)),
11 | url('^ocean/', include(views.OceanViewSet().urls)),
12 | url('^sea/', include(views.SeaViewSet().urls)),
13 | ]
14 |
--------------------------------------------------------------------------------
/demo/integration/views.py:
--------------------------------------------------------------------------------
1 | from django.utils.translation import ugettext_lazy as _
2 |
3 | from material import Layout, Row, Fieldset
4 | from material.frontend.views import ModelViewSet
5 |
6 | from . import models
7 |
8 |
9 | class CityViewSet(ModelViewSet):
10 | model = models.City
11 | ordering = ['-country', 'name']
12 | list_display = ('name', 'country', 'population')
13 |
14 |
15 | class ContinentViewSet(ModelViewSet):
16 | model = models.Continent
17 | list_display = (
18 | 'name', 'surrounded_oceans', 'countries_count',
19 | 'area', 'population', )
20 | layout = Layout(
21 | 'name',
22 | Fieldset(_('Details'),
23 | 'area',
24 | Row('oceans', 'hemisphere'),
25 | Row('population', 'population_density')),
26 | Fieldset(_('Fun facts'),
27 | Row('largest_country', 'biggest_mountain'),
28 | Row('biggest_city', 'longest_river'))
29 | )
30 |
31 | def surrounded_oceans(self, contintent):
32 | return ', '.join(ocean.name for ocean in contintent.oceans.all())
33 | surrounded_oceans.short_description = _('surrounded oceans')
34 |
35 |
36 | class CountryViewSet(ModelViewSet):
37 | model = models.Country
38 | list_display = (
39 | 'tld', 'name', 'continent',
40 | 'became_independent_in_20_century',
41 | 'gay_friendly')
42 | list_display_links = ('tld', 'name', )
43 |
44 | def tld(self, country):
45 | return '.' + country.code.lower()
46 | tld.short_description = 'TLD'
47 |
48 | def became_independent_in_20_century(self, country):
49 | if country.independence_day:
50 | return 1900 <= country.independence_day.year <= 2000
51 | became_independent_in_20_century.short_description = _('became independent in XX century')
52 |
53 |
54 | class OceanViewSet(ModelViewSet):
55 | model = models.Ocean
56 | list_display = ('name', 'area', )
57 |
58 |
59 | class SeaViewSet(ModelViewSet):
60 | model = models.Sea
61 | list_display = ('name', 'parent', 'ocean', 'sea_area', )
62 | layout = Layout(
63 | Row('name', 'parent'),
64 | 'ocean',
65 | Row('area', 'avg_depth', 'max_depth'),
66 | 'basin_countries'
67 | )
68 |
69 | def sea_area(self, sea):
70 | return None if sea.area == 0 else sea.area
71 | sea_area.short_description = _('sea area')
72 |
--------------------------------------------------------------------------------
/demo/leave/__init__.py:
--------------------------------------------------------------------------------
1 | default_app_config = 'demo.leave.apps.LeaveConfig'
--------------------------------------------------------------------------------
/demo/leave/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from .models import *
3 | # Register your models here.
4 | @admin.register(Leave)
5 | class LeaveAdmin(admin.ModelAdmin):
6 | list_display = ('req_by', 'req_date', 'resion')
7 | list_filter = ('req_by','depart_name','req_class')
8 | search_fields = ('resion',)
9 |
10 | @admin.register(LeaveProcess)
11 | class LeaveProcessAdmin(admin.ModelAdmin):
12 | list_display = ('req_by','req_date', 'resion', 'dep_approved', 'hr_approved')
13 | def req_by(self, LeaveProcess):
14 | return LeaveProcess.leave.req_by
15 | def req_date(self, LeaveProcess):
16 | return LeaveProcess.leave.req_date
17 | def resion(self, LeaveProcess):
18 | return LeaveProcess.leave.resion
19 |
20 | @admin.register(Leave_class)
21 | class Leave_classAdmin(admin.ModelAdmin):
22 | pass
--------------------------------------------------------------------------------
/demo/leave/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 | from material.frontend.apps import ModuleMixin
3 | from django.utils.translation import ugettext_lazy as _
4 |
5 |
6 | class LeaveConfig(AppConfig,ModuleMixin):
7 | name = 'demo.leave'
8 | icon = 'backup '
9 | verbose_name = _("请假")
10 |
11 |
12 |
--------------------------------------------------------------------------------
/demo/leave/flows.py:
--------------------------------------------------------------------------------
1 | from viewflow import flow, frontend
2 | from viewflow.base import this, Flow
3 | from viewflow.flow.views import CreateProcessView, UpdateProcessView
4 | from viewflow.flow import views as flow_views
5 |
6 | from .models import *
7 | from .views import *
8 |
9 | @frontend.register
10 | class LeaveFlow(Flow):
11 | process_class = LeaveProcess
12 | summary_template = "{{ process.leave.req_by.user.username }}的请假"
13 | process_title = '请假'
14 |
15 | start = (
16 | flow.Start(
17 | LeaveStartView
18 | ).Permission(
19 | auto_create=True
20 | ).Next(this.dep_approve)
21 | )
22 |
23 | dep_approve = (
24 | flow.View(
25 | approve_check
26 | ).Assign(
27 | #提交到自己的manager
28 | lambda act: act.process.leave.req_by.Manager.user
29 | ).Next(
30 | this.check_dep_approve)
31 | )
32 |
33 | check_dep_approve = (
34 | flow.If(lambda activation: activation.process.dep_approved==1)
35 | .Then(this.hr_approve)
36 | .Else(this.NG)
37 | )
38 |
39 | hr_approve = (
40 | flow.View(
41 | approve_check
42 | ).Permission(
43 | #有权限就可以签收,给特定的人赋权就可以。
44 | auto_create=True
45 | ).Next(
46 | this.check_hr_approve
47 | )
48 | )
49 |
50 | check_hr_approve = (
51 | flow.If(lambda activation: activation.process.hr_approved==1)
52 | .Then(this.OK)
53 | .Else(this.NG)
54 | )
55 | NG = (
56 | flow.Handler(
57 | this.send_NG_request
58 | ).Next(this.end)
59 | )
60 | OK = (
61 | flow.Handler(
62 | this.send_OK_request
63 | ).Next(this.end)
64 | )
65 |
66 | end = flow.End()
67 |
68 | def send_NG_request(self, activation):
69 | print('dep_approved==>'+ str(activation.process.dep_approved))
70 | print('hr_approved==>' + str(activation.process.hr_approved))
71 | print('NG')
72 |
73 | def send_OK_request(self, activation):
74 | #print(activation.process.leave.user)
75 | print('OK')
--------------------------------------------------------------------------------
/demo/leave/forms.py:
--------------------------------------------------------------------------------
1 | from django import forms
2 | from material import *
3 |
4 | from . import models
5 |
6 |
7 | class LeaveForm(forms.ModelForm):
8 | def __init__(self, *args, **kwargs):
9 | super(LeaveForm, self).__init__(*args, **kwargs)
10 | instance = getattr(self, 'instance', None)
11 | #不起作用
12 | if instance and instance.id:
13 | self.fields['req_by'].widget.attrs['disabled'] = True
14 | self.fields['position'].widget.attrs['readonly'] = True
15 | self.fields['depart_name'].widget.attrs['disabled'] = True
16 | self.fields['req_date'].widget.attrs['disabled'] = True
17 |
18 |
19 | class Meta:
20 | model = models.Leave
21 | fields = ['req_by','depart_name','position','req_date','req_class','file_url','start_time','end_time','resion',]
22 | widgets = {
23 | 'password': forms.PasswordInput()
24 | }
25 |
26 | class LeaveDepCheckForm(forms.ModelForm):
27 |
28 | def __init__(self, *args, **kwargs):
29 | super(LeaveDepCheckForm, self).__init__(*args, **kwargs)
30 | instance = getattr(self, 'instance', None)
31 | if instance and instance.id:
32 | self.fields['position'].widget.attrs['readonly'] = True
33 | self.fields['resion'].widget.attrs['readonly'] = True
34 | self.fields['file_url'].widget.attrs['readonly'] = True
35 | self.fields['req_by'].widget.attrs['disabled'] = True
36 | self.fields['depart_name'].widget.attrs['disabled'] = True
37 | self.fields['req_date'].widget.attrs['disabled'] = True
38 | self.fields['start_time'].widget.attrs['disabled'] = True
39 | self.fields['end_time'].widget.attrs['disabled'] = True
40 | self.fields['req_class'].widget.attrs['disabled'] = True
41 |
42 |
43 | layout = Layout(
44 | Row(Span2('req_by'), 'depart_name', Span2('position'),'req_date'),
45 | Row('req_class', 'file_url'),
46 | Row('start_time','end_time'),
47 | 'resion',
48 | 'dep_approved',
49 | 'dep_approved_comment',
50 | )
51 | dep_approved =forms.ChoiceField(label='部门审核',choices=((1, "同意"),
52 | (-1, "不同意"),))
53 | dep_approved_comment = forms.CharField(label='审核意见',widget=forms.Textarea)
54 |
55 | class Meta:
56 | model = models.Leave
57 | fields = ['req_by','depart_name', 'position', 'req_date', 'req_class', 'file_url', 'start_time', 'end_time', 'resion', 'dep_approved','dep_approved_comment']
58 |
59 |
60 |
61 | class LeaveHrCheckForm(LeaveDepCheckForm):
62 |
63 | class Meta:
64 | model = models.Leave
65 | fields = ['req_by','depart_name', 'position', 'req_date', 'req_class', 'file_url', 'start_time', 'end_time', 'resion', 'dep_approved','dep_approved_comment','hr_approved','hr_approved_comment']
66 |
67 |
68 | layout = Layout(
69 | Row(Span2('req_by'), 'depart_name', Span2('position'),'req_date'),
70 | Row('req_class', 'file_url'),
71 | Row('start_time','end_time'),
72 | 'resion',
73 | 'dep_approved',
74 | 'dep_approved_comment',
75 | 'hr_approved',
76 | 'hr_approved_comment',
77 | )
78 |
79 | hr_approved =forms.ChoiceField(label='人事审核',choices=((1, "同意"),
80 | (-1, "不同意"),))
81 | hr_approved_comment = forms.CharField(label='审核意见',widget=forms.Textarea)
82 |
83 | def __init__(self, *args, **kwargs):
84 | super(LeaveHrCheckForm, self).__init__(*args, **kwargs)
85 | instance = getattr(self, 'instance', None)
86 | if instance and instance.id:
87 | self.fields['dep_approved'].widget.attrs['disabled'] = True
88 | self.fields['dep_approved_comment'].widget.attrs['readonly'] = True
--------------------------------------------------------------------------------
/demo/leave/migrations/0001_initial.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.11.7 on 2017-11-24 07:47
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 | ('viewflow', '0006_i18n'),
15 | ('hr', '0001_initial'),
16 | ]
17 |
18 | operations = [
19 | migrations.CreateModel(
20 | name='Leave',
21 | fields=[
22 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
23 | ('req_date', models.DateTimeField(verbose_name='申请时间')),
24 | ('position', models.CharField(max_length=256, verbose_name='职位')),
25 | ('start_time', models.DateTimeField(verbose_name='开始时间')),
26 | ('end_time', models.DateTimeField(verbose_name='结束时间')),
27 | ('resion', models.CharField(max_length=256, verbose_name='请假事由')),
28 | ('file_url', models.CharField(max_length=256, verbose_name='上传附件')),
29 | ('depart_name', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hr.department', verbose_name='部门')),
30 | ('req_by', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='hr.employee', verbose_name='申请人')),
31 | ],
32 | options={
33 | 'verbose_name': '请假',
34 | 'verbose_name_plural': '请假',
35 | 'db_table': 'leave',
36 | },
37 | ),
38 | migrations.CreateModel(
39 | name='Leave_class',
40 | fields=[
41 | ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
42 | ('name', models.CharField(max_length=256, verbose_name='名称')),
43 | ],
44 | options={
45 | 'verbose_name': '请假类别',
46 | 'verbose_name_plural': '请假类别',
47 | 'db_table': 'leave_class',
48 | },
49 | ),
50 | migrations.CreateModel(
51 | name='LeaveProcess',
52 | fields=[
53 | ('process_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='viewflow.Process')),
54 | ('dep_approved', models.BooleanField(default=False, verbose_name='部门审核')),
55 | ('dep_approved_time', models.DateTimeField(blank=True, null=True, verbose_name='部门领导审核时间')),
56 | ('dep_approved_comment', models.CharField(blank=True, max_length=256, null=True, verbose_name='部门领导审核意见')),
57 | ('hr_approved', models.BooleanField(default=False, verbose_name='人事审核')),
58 | ('hr_approved_time', models.DateTimeField(blank=True, null=True, verbose_name='人事审核时间')),
59 | ('hr_approved_comment', models.CharField(blank=True, max_length=256, null=True, verbose_name='人事审核意见')),
60 | ('comment', models.CharField(blank=True, max_length=1024, null=True)),
61 | ('leave', models.OneToOneField(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='leave.Leave')),
62 | ],
63 | options={
64 | 'verbose_name': '请假过程',
65 | 'verbose_name_plural': '请假过程',
66 | 'db_table': 'leave_process',
67 | },
68 | bases=('viewflow.process',),
69 | ),
70 | migrations.AddField(
71 | model_name='leave',
72 | name='req_class',
73 | field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='leave.Leave_class', verbose_name='请假类别'),
74 | ),
75 | ]
76 |
--------------------------------------------------------------------------------
/demo/leave/migrations/0002_leave_comment.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.11.7 on 2017-11-29 09:41
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('leave', '0001_initial'),
12 | ]
13 |
14 | operations = [
15 | migrations.AddField(
16 | model_name='leave',
17 | name='comment',
18 | field=models.CharField(blank=True, max_length=256, null=True, verbose_name='备注'),
19 | ),
20 | ]
21 |
--------------------------------------------------------------------------------
/demo/leave/migrations/0003_auto_20171130_0922.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | # Generated by Django 1.11.7 on 2017-11-30 01:22
3 | from __future__ import unicode_literals
4 |
5 | from django.db import migrations, models
6 |
7 |
8 | class Migration(migrations.Migration):
9 |
10 | dependencies = [
11 | ('leave', '0002_leave_comment'),
12 | ]
13 |
14 | operations = [
15 | migrations.AlterField(
16 | model_name='leaveprocess',
17 | name='dep_approved',
18 | field=models.IntegerField(default=0, verbose_name='部门审核'),
19 | ),
20 | migrations.AlterField(
21 | model_name='leaveprocess',
22 | name='hr_approved',
23 | field=models.IntegerField(default=0, verbose_name='人事审核'),
24 | ),
25 | ]
26 |
--------------------------------------------------------------------------------
/demo/leave/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/leave/migrations/__init__.py
--------------------------------------------------------------------------------
/demo/leave/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from viewflow.models import Process
3 | from demo.hr.models import *
4 |
5 |
6 | class Leave_class(models.Model):
7 | name= models.CharField(max_length=256, verbose_name=u"名称")
8 | class Meta:
9 | db_table = 'leave_class'
10 | verbose_name = '请假类别'
11 | verbose_name_plural = "请假类别"
12 |
13 |
14 |
15 | def __str__(self):
16 | return self.name
17 |
18 |
19 | # class department(models.Model):
20 | # name = models.CharField(max_length=256, verbose_name=u"名称")
21 | # leader = models.ForeignKey(User, verbose_name=u"部门经理")
22 | #
23 | # class Meta:
24 | # db_table = 'department'
25 | # verbose_name = '部门'
26 | # verbose_name_plural = "部门"
27 | #
28 | # def __str__(self):
29 | # return self.name
30 |
31 | class Leave(models.Model):
32 | """请假内容"""
33 | req_by = models.ForeignKey(employee, verbose_name=u"申请人")
34 | req_date = models.DateTimeField(verbose_name=u"申请时间")
35 | depart_name = models.ForeignKey(department,verbose_name=u'部门')
36 | position = models.CharField(max_length=256, verbose_name=u"职位")
37 | req_class =models.ForeignKey(Leave_class,verbose_name=u'请假类别')
38 | start_time=models.DateTimeField(verbose_name=u"开始时间")
39 | end_time=models.DateTimeField(verbose_name=u"结束时间")
40 | resion=models.CharField(max_length=256, verbose_name=u"请假事由")
41 | file_url=models.CharField(max_length=256, verbose_name=u"上传附件")
42 | comment = models.CharField(max_length=256, verbose_name=u"备注",blank=True,null=True)
43 | #审批领导
44 |
45 | class Meta:
46 | db_table = 'leave'
47 | verbose_name = '请假'
48 | verbose_name_plural = "请假"
49 |
50 | def __str__(self):
51 | return self.req_by.user.username
52 |
53 |
54 | class LeaveProcess(Process):
55 |
56 | leave = models.OneToOneField(Leave,null=True,blank=True)
57 |
58 | dep_approved = models.IntegerField(default=0, verbose_name=u"部门审核")
59 | dep_approved_time = models.DateTimeField(verbose_name=u"部门领导审核时间",blank=True,null=True)
60 | dep_approved_comment = models.CharField(max_length=256, verbose_name=u"部门领导审核意见",blank=True,null=True)
61 |
62 | hr_approved = models.IntegerField(default=0, verbose_name=u"人事审核")
63 | hr_approved_time = models.DateTimeField(verbose_name=u"人事审核时间",blank=True,null=True)
64 | hr_approved_comment= models.CharField(max_length=256, verbose_name=u"人事审核意见",blank=True,null=True)
65 | comment=models.CharField(max_length=1024,blank=True,null=True)
66 |
67 | class Meta:
68 | db_table = 'leave_process'
69 | verbose_name = '请假过程'
70 | verbose_name_plural = "请假过程"
71 |
--------------------------------------------------------------------------------
/demo/leave/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/demo/leave/urls.py:
--------------------------------------------------------------------------------
1 | from .views import *
2 | from .flows import LeaveFlow
3 | from django.conf.urls import url, include
4 | from django.views import generic
5 |
6 |
7 | urlpatterns = [
8 | url('^$', generic.RedirectView.as_view(url='./leave/'), name="index"),
9 | url('^leave/', include(LeaveFlowViewSet(LeaveFlow).urls),name="leave"),
10 | url('^leave/action/delete/(?P\d+)/$',LeaveDel, name="delete"),
11 | ]
12 |
--------------------------------------------------------------------------------
/demo/settings.py:
--------------------------------------------------------------------------------
1 | import os
2 | import django
3 | BASE_DIR = os.path.dirname(os.path.dirname(__file__))
4 |
5 |
6 | # Quick-start development settings - unsuitable for production
7 | # See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/
8 |
9 | # SECURITY WARNING: keep the secret key used in production secret!
10 | SECRET_KEY = 'ratn!684yf7ewt-%j%afwf7et9c=!oan$=w6#)fn#4u$ie4!as'
11 |
12 | # SECURITY WARNING: don't run with debug turned on in production!
13 | DEBUG = True
14 |
15 | ALLOWED_HOSTS = []
16 |
17 | INTERNAL_IPS = [
18 | '127.0.0.1'
19 | ]
20 |
21 | # Application definition
22 |
23 | INSTALLED_APPS = (
24 | # viewflow
25 | 'viewflow.frontend',
26 | 'viewflow',
27 |
28 | # material
29 | 'material',
30 | 'material.frontend',
31 | 'material.admin',
32 |
33 | # django
34 | 'django.contrib.admin',
35 | 'django.contrib.auth',
36 | 'django.contrib.contenttypes',
37 | 'django.contrib.sessions',
38 | 'django.contrib.messages',
39 | 'django.contrib.staticfiles',
40 | 'demo.bloodtest',
41 | 'demo.customnode',
42 | 'demo.leave',
43 | 'demo.hr',
44 | 'demo.countersign',
45 | 'demo.integration',
46 | 'demo.employees',
47 | 'demo.testing',
48 | #'demo.shipment',
49 | )
50 |
51 | MIDDLEWARE_CLASSES = (
52 | 'django.contrib.sessions.middleware.SessionMiddleware',
53 | 'django.middleware.locale.LocaleMiddleware',
54 | 'django.middleware.common.CommonMiddleware',
55 | 'django.middleware.csrf.CsrfViewMiddleware',
56 | 'django.contrib.auth.middleware.AuthenticationMiddleware',
57 | 'django.contrib.messages.middleware.MessageMiddleware',
58 | 'django.middleware.clickjacking.XFrameOptionsMiddleware',
59 | 'material.frontend.middleware.SmoothNavigationMiddleware',
60 | )
61 |
62 | ROOT_URLCONF = 'demo.urls'
63 |
64 | LOGIN_REDIRECT_URL = '/workflow/'
65 |
66 | # Database
67 | # https://docs.djangoproject.com/en/1.6/ref/settings/#databases
68 | import dj_database_url # NOQA
69 |
70 | DATABASES = {
71 | 'default': dj_database_url.config() or {
72 | 'ENGINE': 'django.db.backends.sqlite3',
73 | 'NAME': os.path.join(BASE_DIR, 'db{}{}.sqlite3'.format(*django.VERSION[:2])),
74 | }
75 | }
76 |
77 | # Templates
78 |
79 | TEMPLATES = [
80 | {
81 | 'BACKEND': 'django.template.backends.django.DjangoTemplates',
82 | 'DIRS': [
83 | os.path.join(BASE_DIR, 'demo/templates'),
84 | ],
85 | 'APP_DIRS': True,
86 | 'OPTIONS': {
87 | 'context_processors': [
88 | 'django.template.context_processors.debug',
89 | 'django.template.context_processors.request',
90 | 'django.contrib.auth.context_processors.auth',
91 | 'django.contrib.messages.context_processors.messages',
92 | 'django.template.context_processors.request',
93 | 'demo.website.users',
94 | 'demo.website.testing_types',
95 | 'material.frontend.context_processors.modules',
96 | ],
97 | 'debug': True,
98 | },
99 | },
100 | ]
101 |
102 | # Internationalization
103 | # https://docs.djangoproject.com/en/1.6/topics/i18n/
104 |
105 | LANGUAGE_CODE = 'zh-hans'
106 |
107 | # TIME_ZONE = 'UTC'
108 | TIME_ZONE = 'Asia/Shanghai'
109 |
110 | USE_I18N = True
111 |
112 | USE_L10N = True
113 |
114 | USE_TZ = True
115 |
116 | # South
117 | if django.VERSION < (1, 7):
118 | INSTALLED_APPS += ('south', )
119 |
120 | # Static files (CSS, JavaScript, Images)
121 | # https://docs.djangoproject.com/en/1.6/howto/static-files/
122 |
123 | STATIC_URL = '/static/'
124 |
125 | STATICFILES_DIRS = [
126 | os.path.join(BASE_DIR, "demo", "static"),
127 | ]
128 |
129 | try:
130 | from demo.local_settings import * # NOQA
131 | except ImportError:
132 | pass
133 |
--------------------------------------------------------------------------------
/demo/static/demo/css/vfOA.css:
--------------------------------------------------------------------------------
1 | span.approve_ok_icon{height:20px; width:20px; display:block; position:relative;}
2 | span.approve_ok_icon:after, .approve_ok_icon:before{content:''; height:14px; width:3px; display:block; background:#333; position:absolute; top:3px; left:10px; border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px; transform:rotate(45deg);-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-o-transform:rotate(45deg);-ms-transform:rotate(45deg);}
3 | span.approve_ok_icon:before{height:6px; transform:rotate(-45deg);-webkit-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-o-transform:rotate(-45deg);-ms-transform:rotate(-45deg); top:9px; left:4px;}
4 | span.approve_ng_icon{height:20px; width:20px; display:block; position:relative;}
5 | span.approve_ng_icon:before, .approve_ng_icon:after{content:''; height:4px; width:20px; display:block; background:#333; border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px; position:absolute; top:8px; left:0px; transform:rotate(-45deg);-webkit-transform:rotate(-45deg);-moz-transform:rotate(-45deg);-o-transform:rotate(-45deg);-ms-transform:rotate(-45deg);}
6 | span.approve_ng_icon:after{transform:rotate(45deg);-webkit-transform:rotate(45deg);-moz-transform:rotate(45deg);-o-transform:rotate(45deg);-ms-transform:rotate(45deg);}
--------------------------------------------------------------------------------
/demo/static/demo/js/jquery.cookie.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * jQuery Cookie Plugin v1.4.1
3 | * https://github.com/carhartl/jquery-cookie
4 | *
5 | * Copyright 2013 Klaus Hartl
6 | * Released under the MIT license
7 | */
8 | !function(a){"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports?require("jquery"):jQuery)}(function(a){function b(a){return h.raw?a:encodeURIComponent(a)}function c(a){return h.raw?a:decodeURIComponent(a)}function d(a){return b(h.json?JSON.stringify(a):String(a))}function e(a){0===a.indexOf('"')&&(a=a.slice(1,-1).replace(/\\"/g,'"').replace(/\\\\/g,"\\"));try{return a=decodeURIComponent(a.replace(g," ")),h.json?JSON.parse(a):a}catch(b){}}function f(b,c){var d=h.raw?b:e(b);return a.isFunction(c)?c(d):d}var g=/\+/g,h=a.cookie=function(e,g,i){if(void 0!==g&&!a.isFunction(g)){if(i=a.extend({},h.defaults,i),"number"==typeof i.expires){var j=i.expires,k=i.expires=new Date;k.setTime(+k+864e5*j)}return document.cookie=[b(e),"=",d(g),i.expires?"; expires="+i.expires.toUTCString():"",i.path?"; path="+i.path:"",i.domain?"; domain="+i.domain:"",i.secure?"; secure":""].join("")}for(var l=e?void 0:{},m=document.cookie?document.cookie.split("; "):[],n=0,o=m.length;o>n;n++){var p=m[n].split("="),q=c(p.shift()),r=p.join("=");if(e&&e===q){l=f(r,g);break}e||void 0===(r=f(r))||(l[q]=r)}return l};h.defaults={},a.removeCookie=function(b,c){return void 0===a.cookie(b)?!1:(a.cookie(b,"",a.extend({},c,{expires:-1})),!a.cookie(b))}});
--------------------------------------------------------------------------------
/demo/templates/demo/base_module.html:
--------------------------------------------------------------------------------
1 | {% extends 'material/frontend/base_module.html' %}
2 | {% load static viewflow_frontend %}
3 | {% block extracss %}
4 |
5 | {% endblock %}
6 |
--------------------------------------------------------------------------------
/demo/templates/demo/index.html:
--------------------------------------------------------------------------------
1 | {% extends 'demo/base_module.html' %}
2 |
3 | {% block content %}
4 |
5 |
28 |
29 |
30 |
VfOA
31 |
基于Viewflow的OA演示系统,能够快速实现数据的CURD以及流程处理,可开发轻量级OA/CRM/ERP等系统
32 |
33 |
34 |
35 |
36 | {% endblock content %}
37 |
--------------------------------------------------------------------------------
/demo/templates/hr/menu.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/demo/templates/leave/check.html:
--------------------------------------------------------------------------------
1 | {% extends 'viewflow/flow/task.html' %}
--------------------------------------------------------------------------------
/demo/templates/leave/menu.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/demo/templates/leave/start.html:
--------------------------------------------------------------------------------
1 | {% extends 'viewflow/flow/start.html' %}
2 | {% load viewflow material_form material_frontend %}
3 | {% load i18n viewflow material_form %}
4 |
5 | {% block left-panel %}
6 |
34 | {% endblock %}
35 |
--------------------------------------------------------------------------------
/demo/templates/material/fields/_django_rangeinput.html:
--------------------------------------------------------------------------------
1 | {% load material_form material_form_internal l10n %}
2 | {% part bound_field.field %}
3 |
7 | {% part field label %}
8 |
{{ bound_field.label }}
12 | {% endpart %}
13 | {% part field prefix %}{% endpart %}{% part field control %}
14 |
15 |
{% endpart %}
22 | {% part field help_text %}{% if field.help_text %}
23 |
{{ bound_field.help_text|safe }}
24 | {% endif %}
25 | {% endpart %}{% part field errors %}
26 | {% if bound_field.errors %}{% include 'material/field_errors.html' %}{% endif %}
27 | {% endpart %}{{ hidden_initial }}
28 |
29 |
{% endpart %}
30 |
--------------------------------------------------------------------------------
/demo/templates/material/fields/django_checkboxinput.html:
--------------------------------------------------------------------------------
1 | {% load material_form material_form_internal %}
2 | {% part bound_field.field %}
3 |
7 | {% part field prefix %}{% endpart %}{% part field control %}
8 |
{% endpart %}{% part field label %}
15 |
{{ bound_field.label }} {% endpart %}
18 | {% part field help_text %}{% part field errors %}
19 | {% if bound_field.errors %}
20 | {% include 'material/field_errors.html' %}
21 | {% endif %}{% endpart %}{% if field.help_text %}
22 |
{{ bound_field.help_text|safe }}
23 | {% endif %}
24 | {% endpart %}{{ hidden_initial }}
25 |
26 |
{% endpart %}
27 |
--------------------------------------------------------------------------------
/demo/templates/material/fields/django_checkboxselectmultiple.html:
--------------------------------------------------------------------------------
1 | {% load l10n material_form material_form_internal %}
2 | {% part field columns asvar 'columns' %}1{% endpart %}
3 | {% part bound_field.field %}
4 | {% part field label %}
5 | {{ bound_field.label }}
8 |
{% endpart %}
9 |
13 | {% part field prefix %}{% endpart %}{% part field control %}
14 |
15 | {% for group, items in bound_field|select_options %}{% for col_span, choices in items|split_choices_by_columns:4 %}
16 | {% for choice, value, selected, position in choices %}
17 |
18 |
26 | {{ choice }}
27 |
28 | {% endfor %}
{% endfor %}{% endfor %}
29 |
30 | {% endpart %}{% part field help_text %}{% if field.help_text %}
31 |
{{ bound_field.help_text|safe }}
32 | {% endif %}{% part field errors %}
33 | {% if bound_field.errors %}
34 | {% include 'material/field_errors.html' %}
35 | {% endif %}{% endpart %}
36 | {% endpart %}{{ hidden_initial }}
37 |
38 |
{% endpart %}
39 |
--------------------------------------------------------------------------------
/demo/templates/material/fields/django_clearablefileinput.html:
--------------------------------------------------------------------------------
1 | {% load material_form material_form_internal i18n %}
2 |
3 | {% render bound_field template='fields/django_fileinput.html' %}
4 | {% part bound_field suffix %}
5 | {% if bound_field.value|is_initial_file and not field.required %}
6 |
7 |
8 | {{ field.widget.clear_checkbox_label }}
9 |
10 | {% endif %}
11 | {% endpart %}
12 | {% endrender %}
13 |
--------------------------------------------------------------------------------
/demo/templates/material/fields/django_dateinput.html:
--------------------------------------------------------------------------------
1 | {% load i18n material_form material_form_internal %}
2 | {% get_current_language as LANGUAGE_CODE %}
3 | {% get_language_info for LANGUAGE_CODE as lang %}
4 | {% part bound_field.field %}{% endpart %}
36 |
--------------------------------------------------------------------------------
/demo/templates/material/fields/django_datetimeinput.html:
--------------------------------------------------------------------------------
1 | {% load i18n material_form material_form_internal %}
2 | {% get_current_language as LANGUAGE_CODE %}
3 | {% get_language_info for LANGUAGE_CODE as lang %}
4 | {% part bound_field.field %}{% endpart %}
36 |
--------------------------------------------------------------------------------
/demo/templates/material/fields/django_fileinput.html:
--------------------------------------------------------------------------------
1 | {% load material_form material_form_internal i18n %}
2 | {% part bound_field.field %}{% endpart %}
30 |
--------------------------------------------------------------------------------
/demo/templates/material/fields/django_input.html:
--------------------------------------------------------------------------------
1 | {% load material_form material_form_internal l10n %}
2 | {% if field.widget.input_type == 'range' %}{% include 'material/fields/_django_rangeinput.html'%}{% else %}
3 | {% part bound_field.field %}{% endpart %}{% endif %}
30 |
--------------------------------------------------------------------------------
/demo/templates/material/fields/django_nullbooleanselect.html:
--------------------------------------------------------------------------------
1 | {% load material_form material_form_internal i18n %}
2 |
3 | {% render bound_field template='fields/django_select.html' %}
4 | {% part field options %}{% for value, choice in field.widget.choices %}
5 | {% if value == None or value == '' %}{{ form_select_empty_label|default:choice }}{% else %}{{ choice }}{% endif %} {% endfor %}{% endpart %}
6 | {% endrender %}
7 |
--------------------------------------------------------------------------------
/demo/templates/material/fields/django_radioselect.html:
--------------------------------------------------------------------------------
1 | {% load l10n material_form material_form_internal %}
2 | {% part bound_field.field %}
3 |
4 | {% part field prefix %}{% endpart %}{% part field label %}{{ bound_field.label }} {% endpart %}
5 |
6 |
10 | {% part field control %}
11 | {% for group, items in bound_field|select_options %}{% for choice, value, selected in items %}
12 |
20 | {{ choice }}
24 |
25 | {% endfor %}{% endfor %}{% endpart %}{% part field help_text %}{% if field.help_text %}
26 |
{{ bound_field.help_text|safe }}
27 | {% endif %}{% part field errors %}
28 | {% if bound_field.errors %}
29 | {% include 'material/field_errors.html' %}
30 | {% endif %}{% endpart %}
31 | {% endpart %}{{ hidden_initial }}
32 |
33 |
{% endpart %}
34 |
--------------------------------------------------------------------------------
/demo/templates/material/fields/django_select.html:
--------------------------------------------------------------------------------
1 | {% load l10n material_form material_form_internal %}
2 | {% part bound_field.field %}
3 |
7 | {% part field prefix %}{% endpart %}{% part field label %}
8 |
{{ bound_field.label }}
11 | {% endpart %}
12 | {% part field control %}
13 |
18 | {% part field options %}{% for group, items in bound_field|select_options %}
19 | {% if group %}{% endif %}{% for choice, value, selected in items %}
20 | {% if value == None or value == '' %}{{ form_select_empty_label|default:choice }}{% else %}{{ choice }}{% endif %} {% endfor %}
21 | {% if group %} {% endif %}{% endfor %}{% endpart %}
22 |
23 | {% endpart %}
24 | {% part field help_text %}{% if field.help_text %}
25 |
{{ bound_field.help_text|safe }}
26 | {% endif %}{% endpart %}{% part field errors %}
27 | {% if bound_field.errors %}
28 | {% include 'material/field_errors.html' %}
29 | {% endif %}{% endpart %}{{ hidden_initial }}
30 |
31 |
{% endpart %}
32 |
--------------------------------------------------------------------------------
/demo/templates/material/fields/django_selectdatewidget.html:
--------------------------------------------------------------------------------
1 | {% load material_form material_form_internal %}
2 |
3 |
4 | {% part field label %}
5 |
6 | {{ bound_field.label }}
7 |
8 | {% endpart %}
9 | {% part field prefix %}{% endpart %}
10 | {% part field control %}
11 | {% with bound_field|select_date_widget_wrapper as wrapper %}
12 | {% for select in wrapper.selects %}{% if select.type == "day" %}
13 | {% for value, choice in select.choices %}
18 | {% if value == None or value == '' %}{{ form_select_empty_label|default:choice }}{% else %}{{ choice }}{% endif %} {% endfor %}
19 |
20 |
{% endif %}{% if select.type == "month" %}
21 | {% for value, choice in select.choices %}
26 | {% if value == None or value == '' %}{{ form_select_empty_label|default:choice }}{% else %}{{ choice }}{% endif %} {% endfor %}
27 |
28 |
{% endif %}{% if select.type == "year" %}
29 | {% for value, choice in select.choices %}
34 | {% if value == None or value == '' %}{{ form_select_empty_label|default:choice }}{% else %}{{ choice }}{% endif %} {% endfor %}
35 |
36 |
{% endif %}
37 | {% endfor %}{% endwith %}
38 |
39 | {% part field help_text %}{% if field.help_text %}
40 |
{{ bound_field.help_text|safe }}
41 | {% endif %}{% endpart %}{% part field errors %}
42 | {% if bound_field.errors %}
43 | {% include 'material/field_errors.html' %}
44 | {% endif %}{% endpart %}{{ hidden_initial }}
45 | {% endpart %}
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/demo/templates/material/fields/django_selectmultiple.html:
--------------------------------------------------------------------------------
1 | {% load i18n l10n material_form material_form_internal %}
2 |
3 | {% render bound_field template='fields/django_select.html' %}
4 | {% attr field 'widget' multiple %}True{% endattr %}
5 | {% attr field 'group' class append %}multiselect{% endattr %}
6 | {% part field options %}
7 | {% if not field|have_default_choice %}{% trans "Choose your option" %} {% endif %}{% for group, items in bound_field|select_options %}{% if group %}{% endif %}{% for choice, value, selected in items %}
8 | {% if value == None or value == '' %}{{ form_select_empty_label|default:choice }}{% else %}{{ choice }}{% endif %} {% endfor %}
9 | {% if group %} {% endif %}{% endfor %}
10 | {% endpart %}
11 | {% endrender %}
12 |
--------------------------------------------------------------------------------
/demo/templates/material/fields/django_splitdatetimewidget.html:
--------------------------------------------------------------------------------
1 | {% load i18n material_form material_form_internal %}
2 | {% get_current_language as LANGUAGE_CODE %}
3 | {% get_language_info for LANGUAGE_CODE as lang %}
4 | {% part bound_field.field %}{% part field label %}
5 | {% endpart %}
6 |
7 |
8 | {{ bound_field.label }}
11 |
12 |
38 |
40 | query_builder
41 |
51 |
52 |
{% endpart %}
53 |
--------------------------------------------------------------------------------
/demo/templates/material/fields/django_textarea.html:
--------------------------------------------------------------------------------
1 | {% load material_form material_form_internal %}
2 | {% part bound_field.field %}{% endpart %}
30 |
--------------------------------------------------------------------------------
/demo/templates/material/fields/django_timeinput.html:
--------------------------------------------------------------------------------
1 | {% load i18n material_form material_form_internal %}
2 | {% get_current_language as LANGUAGE_CODE %}
3 | {% get_language_info for LANGUAGE_CODE as lang %}
4 |
37 |
--------------------------------------------------------------------------------
/demo/templates/material/frontend/base_site.html:
--------------------------------------------------------------------------------
1 | {% extends 'material/frontend/base.html' %}
2 | {% load static %}
3 |
4 | {% block title %}vfOA-基于Viewflow的OA演示系统{% endblock %}
5 |
6 | {% block css %}
7 | {{ block.super }}
8 |
9 |
10 |
11 | {% endblock %}
12 |
13 | {% block js %}
14 | {{ block.super }}
15 |
16 |
17 | {% endblock %}
18 |
19 |
20 | {% block topbar_links %}
21 |
22 |
27 | {% endblock %}
28 |
29 |
30 | {% block main %}
31 | {{ block.super }}
32 |
33 | {% include 'demo/wizard.html' %}
34 | {% endblock %}
35 |
--------------------------------------------------------------------------------
/demo/testing/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/testing/__init__.py
--------------------------------------------------------------------------------
/demo/testing/admin.py:
--------------------------------------------------------------------------------
1 | from django.contrib import admin
2 | from django.utils.translation import ugettext_lazy as _
3 | # Register your models here.
4 | import django.utils.timezone as timezone
5 | from django.utils.safestring import mark_safe
6 | from django.contrib import admin
7 | from .models import *
8 | from .forms import *
9 | from django.core.urlresolvers import resolve
10 |
11 | # Register your models here.
12 |
13 |
14 | def complete_tasks(modeladmin, request, queryset):
15 | queryset.update(testing_status='1')
16 | complete_tasks.short_description = '测试完成'
17 |
18 | @admin.register(Contract)
19 | class ContractAdmin(admin.ModelAdmin):
20 |
21 | # def get_urls(self):
22 | # pass
23 |
24 | # def get_fields(self, request, obj=None):
25 | # pass
26 | #-----------------**********************
27 | #formfield_for_manytomany
28 |
29 | #------form---------------
30 | icon = "person "
31 | form = ContractForm
32 | save_as = True
33 | layout = Layout(
34 | Fieldset('检测基本信息',
35 | Row('customer','protocol_no','task_no', 'product_type',),
36 | Row( 'product_num','sample_from', 'sample_to', 'report_get',),
37 | Row('testing_area','report_num',),
38 | Row('testing_class','testing_time_class', 'testing_time',)),
39 | Fieldset('检测依据',Row( 'testing_standards'), Row('testing_items')),
40 | Fieldset('检测费用',Row('testing_fee', 'testing_fee_tax_no','testing_fee_tax_class', ))
41 | )
42 |
43 |
44 | def _get_object_from_request(self,request):
45 |
46 | resolved = resolve(request.path_info)
47 | if resolved.args:
48 | return Contract.objects.get(pk=resolved.args[0])
49 |
50 | return None
51 |
52 | def formfield_for_manytomany(self, db_field, request, **kwargs):
53 |
54 | if db_field.name == 'testing_items':
55 | contract = self._get_object_from_request(request)
56 | if contract is not None:
57 | kwargs["queryset"] = TestingItem.objects.filter(testing_type=contract.testing_type)
58 | else:
59 | testin_type_id = request.GET.get('testing-type','1')
60 | one_type = TestingType.objects.filter(id=testin_type_id)
61 | kwargs["queryset"] = TestingItem.objects.filter(testing_type=one_type)
62 | #kwargs.update({"columns":'5'})
63 | return super(ContractAdmin, self).formfield_for_manytomany(db_field, request, **kwargs)
64 |
65 |
66 |
67 | def save_model(self, request, obj, form, change):
68 | if change:
69 | pass
70 | else:
71 | testin_type_id = request.GET.get('testing-type', '1')
72 | obj.create_datetime = timezone.now()
73 | obj.create_user = request.user
74 | obj.testing_type = TestingType.objects.filter(id=testin_type_id).first()
75 |
76 | super(ContractAdmin, self).save_model(request, obj, form, change)
77 |
78 |
79 | #-------list----------------
80 | list_display = ('protocol_no', 'customer_name', 'create_datetime', 'user_name','operate')
81 | list_filter = ('customer',)
82 | search_fields = ['protocol_no','customer__name','create_user__username']
83 | list_display_links = ['protocol_no',]
84 | filter_horizontal = ('testing_standards',)
85 | readonly_fields = ('operate',)
86 | ordering = ('-create_datetime',)
87 |
88 | actions = [complete_tasks,]
89 |
90 | def customer_name(self, contract):
91 | return contract.customer.name
92 |
93 | def user_name(self, contract):
94 | return contract.create_user.username
95 |
96 |
97 | def operate(self, contract):
98 | return mark_safe('修改 '
99 | ' | 删除 ')
100 |
101 | operate.short_description = _('操作')
102 |
103 |
104 |
105 | @admin.register(Customer)
106 | class CustomerAdmin(admin.ModelAdmin):
107 | list_display = ('name', 'address')
108 |
109 | # list_filter = ('req_by','depart_name','req_class')
110 | # search_fields = ('resion',)
111 |
112 |
113 | @admin.register(TestingItem)
114 | class TestingItemAdmin(admin.ModelAdmin):
115 | pass
116 |
117 | @admin.register(TestingType)
118 | class TestingTypeAdmin(admin.ModelAdmin):
119 | pass
120 |
121 |
122 | @admin.register(TestingStandard)
123 | class TestingStandardAdmin(admin.ModelAdmin):
124 | pass
125 |
126 |
--------------------------------------------------------------------------------
/demo/testing/apps.py:
--------------------------------------------------------------------------------
1 | from django.apps import AppConfig
2 |
3 |
4 | class TestingConfig(AppConfig):
5 | name = 'demo.testing'
6 |
--------------------------------------------------------------------------------
/demo/testing/forms.py:
--------------------------------------------------------------------------------
1 | from django import forms
2 | from material import *
3 |
4 | from . import models
5 |
6 |
7 |
8 | class ContractForm(forms.ModelForm):
9 |
10 | class Meta:
11 | model = models.Contract
12 | fields = ['protocol_no',
13 | 'task_no',
14 | 'product_type',
15 | 'product_num',
16 | 'customer',
17 | 'sample_from',
18 | 'sample_to',
19 | 'report_get',
20 | 'testing_area',
21 | 'report_num',
22 | 'testing_class',
23 | 'testing_time_class',
24 | 'testing_time',
25 | 'testing_standards',
26 | 'testing_items',
27 | 'testing_fee',
28 | 'testing_fee_tax_no',
29 | 'testing_fee_tax_class',
30 | ]
31 | widgets = {
32 | 'testing_items': forms.CheckboxSelectMultiple()
33 | }
34 |
35 |
36 | sample_from = forms.ChoiceField( label='来样方式' , choices=(('1', "送样"),('2', "邮寄"),))
37 | sample_to = forms.ChoiceField( label='样品处理' ,choices=(('1', "自取"),('2', "放弃"),('3', "邮寄"),('4', "留存"),))
38 | report_get = forms.ChoiceField( label='报告领取' ,choices=(('1', "自取"),('2', "邮寄"),))
39 | testing_area = forms.ChoiceField( label='测试地点' ,choices=(('1', "本中心"),('2', "现场"),))
40 | testing_class = forms.ChoiceField(label='检测类别' ,choices=(('1', "委托"),('2', "型检"),('3', "监督"),('4', "仲裁"),('4', "摸底"),('4', "检查"),))
41 | testing_time_class = forms.ChoiceField( label='检测时间' ,choices=(('1', "常规"),('2', "加急"),('2', "特急"),))
42 | testing_fee_tax_class = forms.ChoiceField( label='发票类别' ,choices=(('1', "增值税普通发票"),('2', "增值税专用发票"),))
43 | #testing_times = forms.MultipleChoiceField(label='测试项目A')
44 |
45 |
46 | # def __init__(self, *args, **kwargs):
47 | # super(ContractCreateForm, self).__init__(*args, **kwargs)
48 | # instance = getattr(self, 'instance', None)
49 | # if instance and instance.id:
50 | # self.fields['testing_items'].widget = forms.CheckboxSelectMultiple
--------------------------------------------------------------------------------
/demo/testing/migrations/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/demo/testing/migrations/__init__.py
--------------------------------------------------------------------------------
/demo/testing/models.py:
--------------------------------------------------------------------------------
1 | from django.db import models
2 | from django.contrib.auth.models import User
3 |
4 |
5 |
6 | class TestingStandard(models.Model):
7 |
8 |
9 | name =models.CharField(max_length=10, verbose_name=u"标准名称")
10 | no = models.CharField(max_length=10, verbose_name=u"协议号")
11 | st_class = models.CharField(max_length=1, verbose_name=u"标准类别",choices=(
12 | ("0", "国标"),
13 | ("1", "行标"),
14 | ("2", "企标")))
15 | class Meta:
16 | verbose_name = '标准'
17 | verbose_name_plural = "标准"
18 |
19 |
20 | def __str__(self):
21 | stardard_class = {'0': '国标', '1': '行标', '2': '企标'}
22 | return stardard_class[self.st_class] +" | "+ self.name
23 |
24 | class TestingType(models.Model):
25 | name = models.CharField(max_length=1024, verbose_name=u"测试类型")
26 | mark = models.CharField(max_length=1024, verbose_name=u"备注")
27 |
28 | class Meta:
29 | verbose_name = '测试类型'
30 | verbose_name_plural = "测试类型"
31 |
32 | def __str__(self):
33 | return self.name
34 |
35 | class TestingItem(models.Model):
36 | name = models.CharField(max_length=10, verbose_name=u"测试项名称")
37 | #standard = models.ForeignKey(TestingStandard, verbose_name=u"标准类别")
38 | testing_type = models.ForeignKey(TestingType, verbose_name=u"标准类别")
39 | class Meta:
40 | verbose_name = '测试项目'
41 | verbose_name_plural = "测试项目"
42 |
43 |
44 | def __str__(self):
45 | return self.name
46 |
47 | class TestingItemTemp(models.Model):
48 | name = models.CharField(max_length=10, verbose_name=u"模板名称")
49 | items = models.ManyToManyField(TestingItem,verbose_name=u"测试项目")
50 | class Meta:
51 | verbose_name = '测试项目模板'
52 | verbose_name_plural = "测试项目模板"
53 |
54 |
55 | def __str__(self):
56 | return self.name
57 |
58 |
59 | class Customer(models.Model):
60 | name = models.CharField(max_length=1024, verbose_name=u"单位名称")
61 | address = models.CharField(max_length=1024, verbose_name=u"单位地址")
62 | telephone = models.CharField(max_length=1024, verbose_name=u"电话")
63 | atten = models.CharField(max_length=1024, verbose_name=u"联系人")
64 | postcode = models.CharField(max_length=1024, verbose_name=u"邮编")
65 | fax = models.CharField(max_length=1024, verbose_name=u"传真")
66 |
67 |
68 | class Meta:
69 | verbose_name = '委托单位'
70 | verbose_name_plural = "委托单位"
71 |
72 |
73 | def __str__(self):
74 | return self.name
75 |
76 | # Create your models here.
77 | class Contract(models.Model):
78 | protocol_no = models.CharField(max_length=10, verbose_name=u"协议书编号")
79 | task_no = models.CharField(max_length=10, verbose_name=u"任务流水号")
80 | product_type = models.CharField(max_length=1024, verbose_name=u"产品名称/规格型号")
81 | product_num = models.IntegerField( verbose_name=u"数量")
82 | customer = models.ForeignKey(Customer,related_name='contracts',verbose_name=u"委托单位")
83 | sample_from = models.CharField(max_length=1, verbose_name=u"来样方式")
84 | sample_to = models.CharField(max_length=1, verbose_name=u"样品处理")
85 | report_get = models.CharField(max_length=1, verbose_name=u"报告领取")
86 | testing_area = models.CharField(max_length=1, verbose_name=u"测试地点")
87 | report_num = models.IntegerField( verbose_name=u"报告份数",help_text='份数')
88 | testing_class = models.CharField(max_length=1, verbose_name=u"检测类别")
89 | testing_time_class = models.CharField(max_length=1, verbose_name=u"检测时间")
90 | testing_time = models.IntegerField( verbose_name=u"加急",null =True,blank= True,help_text='工作日')
91 | testing_standards = models.ManyToManyField(TestingStandard,verbose_name=u"检测依据")
92 | testing_items = models.ManyToManyField(TestingItem,verbose_name=u"测试项目")
93 | testing_fee = models.FloatField(verbose_name='测试费用',help_text='元',)
94 | testing_fee_tax_no = models.CharField(max_length=1024, verbose_name=u"发票号")
95 | testing_fee_tax_class = models.CharField(max_length=1, verbose_name=u"发票类别")
96 | testing_status = models.CharField(max_length=1, verbose_name=u"检测状态")
97 | testing_type = models.ForeignKey(TestingType, verbose_name=u"标准类别")
98 | create_user = models.ForeignKey(User,verbose_name=u"创建人")
99 | create_datetime = models.DateTimeField( verbose_name=u"创建日期")
100 |
101 | class Meta:
102 | verbose_name = '协议书'
103 | verbose_name_plural = "协议书"
104 |
105 |
106 | def __str__(self):
107 | return self.protocol_no
108 |
109 |
--------------------------------------------------------------------------------
/demo/testing/tests.py:
--------------------------------------------------------------------------------
1 | from django.test import TestCase
2 |
3 | # Create your tests here.
4 |
--------------------------------------------------------------------------------
/demo/testing/views.py:
--------------------------------------------------------------------------------
1 | from django.shortcuts import render
2 |
3 | # Create your views here.
4 |
--------------------------------------------------------------------------------
/demo/urls.py:
--------------------------------------------------------------------------------
1 | import django
2 | from django.conf.urls import include, url
3 | from django.contrib import admin
4 | from django.contrib.auth import views as auth
5 | from django.views import generic
6 |
7 | from material import frontend
8 | from material.frontend.apps import ModuleMixin
9 | from material.frontend.registry import modules
10 |
11 |
12 |
13 | class Demo(ModuleMixin):
14 | """
15 | Home page module
16 | """
17 | order = 1
18 | label = 'Introduction'
19 | verbose_name = '我的桌面'
20 | icon = 'account_balance '
21 |
22 | @property
23 | def urls(self):
24 | index_view = generic.TemplateView.as_view(template_name='demo/index.html')
25 |
26 | return frontend.ModuleURLResolver(
27 | '^', [url('^$', index_view, name="index")],
28 | module=self, app_name='demo', namespace='demo')
29 |
30 | def index_url(self):
31 | return '/'
32 |
33 | def installed(self):
34 | return True
35 |
36 | modules.register(Demo())
37 |
38 |
39 |
40 | if django.VERSION < (1, 7):
41 | admin.autodiscover()
42 |
43 |
44 | from material.frontend import urls as frontend_urls # NOQA
45 |
46 | urlpatterns = [
47 | url(r'^accounts/login/$', auth.login, name='login'),
48 | url(r'^accounts/logout/$', auth.logout, name='logout'),
49 | url(r'^', include('demo.website')),
50 | url(r'', include(frontend_urls)),
51 | ]
52 |
--------------------------------------------------------------------------------
/demo/website.py:
--------------------------------------------------------------------------------
1 | from django.conf.urls import url
2 | from django.contrib.auth import login, logout
3 | from django.contrib.auth.models import User
4 | from django.http import HttpResponseRedirect
5 | from django.shortcuts import redirect
6 | from django.utils.http import is_safe_url
7 | from .testing.models import TestingType
8 |
9 |
10 | def users(request):
11 | return {
12 | 'users': User.objects.filter(is_active=True).order_by('-username')
13 | }
14 |
15 | def testing_types(request):
16 | return {
17 | 'testing_types':TestingType.objects.all()
18 | }
19 |
20 | def login_as(request):
21 | user = None
22 |
23 | user_pk = request.GET.get('user_pk', None)
24 | if user_pk:
25 | try:
26 | user = User.objects.get(pk=user_pk)
27 | except User.DoesNotExist:
28 | pass
29 |
30 | username = request.GET.get('username', None)
31 | if username:
32 | try:
33 | user = User.objects.get(username=username)
34 | except User.DoesNotExist:
35 | pass
36 |
37 | if user:
38 | user.backend = 'django.contrib.auth.backends.ModelBackend'
39 | login(request, user)
40 | else:
41 | logout(request)
42 |
43 | redirect_to = request.GET.get('next')
44 | if not redirect_to or not is_safe_url(redirect_to):
45 | return redirect('/admin/testing/contract')
46 | else:
47 | return HttpResponseRedirect(redirect_to)
48 |
49 |
50 | urlpatterns = [
51 | url(r'^login_as/$', login_as, name="login_as")
52 | ]
53 |
--------------------------------------------------------------------------------
/img/1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/img/1.PNG
--------------------------------------------------------------------------------
/img/2.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/img/2.PNG
--------------------------------------------------------------------------------
/img/3.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/img/3.PNG
--------------------------------------------------------------------------------
/img/4.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/img/4.PNG
--------------------------------------------------------------------------------
/img/5.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/htwenhe/vfOA/4746a894d0827a48bb42a79e6a8a905dd0d60b65/img/5.PNG
--------------------------------------------------------------------------------
/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", "demo.settings")
7 |
8 | from django.core.management import execute_from_command_line
9 |
10 | execute_from_command_line(sys.argv)
11 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | django==1.11.7
2 | django-filter==1.1.0
3 | django-formtools==2.1
4 | django-material==1.1.1
5 | django-viewflow==1.1.0
6 |
--------------------------------------------------------------------------------