n> 0   product/migrations/0002_auto_20170619_1734.py
  • BIN
      product/migrations/0002_auto_20170619_1734.pyc
  • 0 0
      product/migrations/__init__.py
  • BIN
      product/migrations/__init__.pyc
  • 99 0
      product/models.py
  • BIN
      product/models.pyc
  • 4 0
      product/tests.py
  • 4 0
      product/views.py
  • 39 0
      requirements.txt
  • 0 0
      tamron/__init__.py
  • BIN
      tamron/__init__.pyc
  • 13 0
      tamron/basemodels.py
  • BIN
      tamron/basemodels.pyc
  • 16 0
      tamron/func_settings.py
  • BIN
      tamron/func_settings.pyc
  • 29 0
      tamron/local_settings.py
  • BIN
      tamron/local_settings.pyc
  • 254 0
      tamron/settings.py
  • BIN
      tamron/settings.pyc
  • 300 0
      tamron/static/tamron/js/jswe.js
  • 33 0
      tamron/urls.py
  • BIN
      tamron/urls.pyc
  • 2 0
      tamron/uwsgi.bak/shutdown.sh
  • 2 0
      tamron/uwsgi.bak/startup.sh
  • 27 0
      tamron/uwsgi.bak/tamron.ini
  • 35 0
      tamron/uwsgi.bak/tamron_nginx.conf
  • 15 0
      tamron/uwsgi.bak/uwsgi_params
  • 17 0
      tamron/wsgi.py
  • BIN
      tamron/wsgi.pyc
  • 0 0
      utils/__init__.py
  • BIN
      utils/__init__.pyc
  • 0 0
      utils/error/__init__.py
  • BIN
      utils/error/__init__.pyc
  • 62 0
      utils/error/errno_utils.py
  • BIN
      utils/error/errno_utils.pyc
  • 18 0
      utils/error/response_utils.py
  • BIN
      utils/error/response_utils.pyc
  • 0 0
      utils/redis/__init__.py
  • BIN
      utils/redis/__init__.pyc
  • 6 0
      utils/redis/connect.py
  • BIN
      utils/redis/connect.pyc
  • 68 0
      utils/redis/rkeys.py
  • + 29 - 0
    .editorconfig

    @@ -0,0 +1,29 @@
    1
    +# EditorConfig is awesome: http://EditorConfig.org
    2
    +
    3
    +# top-most EditorConfig file
    4
    +root = true
    5
    +
    6
    +# Unix-style newlines with a newline ending every file
    7
    +[*]
    8
    +end_of_line = lf
    9
    +insert_final_newline = false
    10
    +
    11
    +# 4 space indentation
    12
    +[*.py]
    13
    +indent_style = space
    14
    +indent_size = 4
    15
    +
    16
    +# Tab indentation (no size specified)
    17
    +[*.js]
    18
    +indent_style = space
    19
    +indent_size = 4
    20
    +
    21
    +# Tab indentation (no size specified)
    22
    +[*.html]
    23
    +indent_style = space
    24
    +indent_size = 4
    25
    +
    26
    +# Matches the exact files either package.json or .travis.yml
    27
    +[{package.json,.travis.yml}]
    28
    +indent_style = space
    29
    +indent_size = 2

    + 14 - 0
    .idea/misc.xml

    @@ -0,0 +1,14 @@
    1
    +<?xml version="1.0" encoding="UTF-8"?>
    2
    +<project version="4">
    3
    +  <component name="ProjectLevelVcsManager" settingsEditedManually="false">
    4
    +    <OptionsSetting value="true" id="Add" />
    5
    +    <OptionsSetting value="true" id="Remove" />
    6
    +    <OptionsSetting value="true" id="Checkout" />
    7
    +    <OptionsSetting value="true" id="Update" />
    8
    +    <OptionsSetting value="true" id="Status" />
    9
    +    <OptionsSetting value="true" id="Edit" />
    10
    +    <ConfirmationsSetting value="0" id="Add" />
    11
    +    <ConfirmationsSetting value="0" id="Remove" />
    12
    +  </component>
    13
    +  <component name="ProjectRootManager" version="2" project-jdk-name="Python 2.7.12+ (/usr/bin/python2.7)" project-jdk-type="Python SDK" />
    14
    +</project>

    + 8 - 0
    .idea/modules.xml

    @@ -0,0 +1,8 @@
    1
    +<?xml version="1.0" encoding="UTF-8"?>
    2
    +<project version="4">
    3
    +  <component name="ProjectModuleManager">
    4
    +    <modules>
    5
    +      <module fileurl="file://$PROJECT_DIR$/.idea/tamron.iml" filepath="$PROJECT_DIR$/.idea/tamron.iml" />
    6
    +    </modules>
    7
    +  </component>
    8
    +</project>

    + 26 - 0
    .idea/tamron.iml

    @@ -0,0 +1,26 @@
    1
    +<?xml version="1.0" encoding="UTF-8"?>
    2
    +<module type="PYTHON_MODULE" version="4">
    3
    +  <component name="FacetManager">
    4
    +    <facet type="django" name="Django">
    5
    +      <configuration>
    6
    +        <option name="rootFolder" value="$MODULE_DIR$" />
    7
    +        <option name="settingsModule" value="tamron/settings.py" />
    8
    +        <option name="manageScript" value="manage.py" />
    9
    +        <option name="environment" value="&lt;map/&gt;" />
    10
    +        <option name="commandsToSkip" value="" />
    11
    +      </configuration>
    12
    +    </facet>
    13
    +  </component>
    14
    +  <component name="NewModuleRootManager">
    15
    +    <content url="file://$MODULE_DIR$" />
    16
    +    <orderEntry type="inheritedJdk" />
    17
    +    <orderEntry type="sourceFolder" forTests="false" />
    18
    +  </component>
    19
    +  <component name="TemplatesService">
    20
    +    <option name="TEMPLATE_CONFIGURATION" value="Django" />
    21
    +  </component>
    22
    +  <component name="TestRunnerService">
    23
    +    <option name="projectConfiguration" value="py.test" />
    24
    +    <option name="PROJECT_TEST_RUNNER" value="py.test" />
    25
    +  </component>
    26
    +</module>

    + 634 - 0
    .idea/workspace.xml

    @@ -0,0 +1,634 @@
    1
    +<?xml version="1.0" encoding="UTF-8"?>
    2
    +<project version="4">
    3
    +  <component name="ChangeListManager">
    4
    +    <list default="true" id="8287082c-5144-4790-9da1-578e292318f7" name="Default" comment="" />
    5
    +    <ignored path="tamron.iws" />
    6
    +    <ignored path=".idea/workspace.xml" />
    7
    +    <ignored path=".idea/dataSources.local.xml" />
    8
    +    <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
    9
    +    <option name="TRACKING_ENABLED" value="true" />
    10
    +    <option name="SHOW_DIALOG" value="false" />
    11
    +    <option name="HIGHLIGHT_CONFLICTS" value="true" />
    12
    +    <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
    13
    +    <option name="LAST_RESOLUTION" value="IGNORE" />
    14
    +  </component>
    15
    +  <component name="CreatePatchCommitExecutor">
    16
    +    <option name="PATCH_PATH" value="" />
    17
    +  </component>
    18
    +  <component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
    19
    +  <component name="FavoritesManager">
    20
    +    <favorites_list name="tamron" />
    21
    +  </component>
    22
    +  <component name="FileEditorManager">
    23
    +    <leaf>
    24
    +      <file leaf-file-name="tamron.ini" pinned="false" current-in-tab="false">
    25
    +        <entry file="file://$PROJECT_DIR$/tamron/uwsgi.bak/tamron.ini">
    26
    +          <provider selected="true" editor-type-id="text-editor">
    27
    +            <state relative-caret-position="255">
    28
    +              <caret line="17" column="61" selection-start-line="17" selection-start-column="61" selection-end-line="17" selection-end-column="61" />
    29
    +              <folding />
    30
    +            </state>
    31
    +          </provider>
    32
    +        </entry>
    33
    +      </file>
    34
    +      <file leaf-file-name="tamron_nginx.conf" pinned="false" current-in-tab="true">
    35
    +        <entry file="file://$PROJECT_DIR$/tamron/uwsgi.bak/tamron_nginx.conf">
    36
    +          <provider selected="true" editor-type-id="text-editor">
    37
    +            <state relative-caret-position="480">
    38
    +              <caret line="32" column="50" selection-start-line="32" selection-start-column="50" selection-end-line="32" selection-end-column="50" />
    39
    +              <folding />
    40
    +            </state>
    41
    +          </provider>
    42
    +        </entry>
    43
    +      </file>
    44
    +    </leaf>
    45
    +  </component>
    46
    +  <component name="FileTemplateManagerImpl">
    47
    +    <option name="RECENT_TEMPLATES">
    48
    +      <list>
    49
    +        <option value="Python Script" />
    50
    +      </list>
    51
    +    </option>
    52
    +  </component>
    53
    +  <component name="IdeDocumentHistory">
    54
    +    <option name="CHANGED_PATHS">
    55
    +      <list>
    56
    +        <option value="$PROJECT_DIR$/tamron/basemodels.py" />
    57
    +        <option value="$PROJECT_DIR$/account/admin.py" />
    58
    +        <option value="$PROJECT_DIR$/product/admin.py" />
    59
    +        <option value="$PROJECT_DIR$/integral/admin.py" />
    60
    +        <option value="$PROJECT_DIR$/page/views.py" />
    61
    +        <option value="$PROJECT_DIR$/product/models.py" />
    62
    +        <option value="$PROJECT_DIR$/integral/models.py" />
    63
    +        <option value="$PROJECT_DIR$/tamron/settings.py" />
    64
    +        <option value="$PROJECT_DIR$/api/urls.py" />
    65
    +        <option value="$PROJECT_DIR$/tamron/local_settings.py" />
    66
    +        <option value="$PROJECT_DIR$/page/templates/page/clerk_oauth.html" />
    67
    +        <option value="$PROJECT_DIR$/page/sale_views.py" />
    68
    +        <option value="$PROJECT_DIR$/page/templates/page/clerk_sale.html" />
    69
    +        <option value="$PROJECT_DIR$/page/templates/page/clerk_into.html" />
    70
    +        <option value="$PROJECT_DIR$/tamron/urls.py" />
    71
    +        <option value="$PROJECT_DIR$/page/info_views.py" />
    72
    +        <option value="$PROJECT_DIR$/utils/error/errno_utils.py" />
    73
    +        <option value="$PROJECT_DIR$/page/oauth_views.py" />
    74
    +        <option value="$PROJECT_DIR$/account/models.py" />
    75
    +        <option value="$PROJECT_DIR$/page/templates/page/clerk_info.html" />
    76
    +        <option value="$PROJECT_DIR$/tamron/uwsgi.bak/tamron.ini" />
    77
    +        <option value="$PROJECT_DIR$/tamron/uwsgi.bak/tamron_nginx.conf" />
    78
    +      </list>
    79
    +    </option>
    80
    +  </component>
    81
    +  <component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
    82
    +  <component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" />
    83
    +  <component name="JsGulpfileManager">
    84
    +    <detection-done>true</detection-done>
    85
    +    <sorting>DEFINITION_ORDER</sorting>
    86
    +  </component>
    87
    +  <component name="ProjectFrameBounds">
    88
    +    <option name="x" value="65" />
    89
    +    <option name="y" value="24" />
    90
    +    <option name="width" value="1301" />
    91
    +    <option name="height" value="744" />
    92
    +  </component>
    93
    +  <component name="ProjectLevelVcsManager" settingsEditedManually="false">
    94
    +    <OptionsSetting value="true" id="Add" />
    95
    +    <OptionsSetting value="true" id="Remove" />
    96
    +    <OptionsSetting value="true" id="Checkout" />
    97
    +    <OptionsSetting value="true" id="Update" />
    98
    +    <OptionsSetting value="true" id="Status" />
    99
    +    <OptionsSetting value="true" id="Edit" />
    100
    +    <ConfirmationsSetting value="0" id="Add" />
    101
    +    <ConfirmationsSetting value="0" id="Remove" />
    102
    +  </component>
    103
    +  <component name="ProjectView">
    104
    +    <navigator currentView="ProjectPane" proportions="" version="1">
    105
    +      <flattenPackages />
    106
    +      <showMembers />
    107
    +      <showModules />
    108
    +      <showLibraryContents />
    109
    +      <hideEmptyPackages />
    110
    +      <abbreviatePackageNames />
    111
    +      <autoscrollToSource />
    112
    +      <autoscrollFromSource />
    113
    +      <sortByType />
    114
    +      <manualOrder />
    115
    +      <foldersAlwaysOnTop value="true" />
    116
    +    </navigator>
    117
    +    <panes>
    118
    +      <pane id="Scratches" />
    119
    +      <pane id="Scope" />
    120
    +      <pane id="ProjectPane">
    121
    +        <subPane>
    122
    +          <PATH>
    123
    +            <PATH_ELEMENT>
    124
    +              <option name="myItemId" value="tamron" />
    125
    +              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
    126
    +            </PATH_ELEMENT>
    127
    +          </PATH>
    128
    +          <PATH>
    129
    +            <PATH_ELEMENT>
    130
    +              <option name="myItemId" value="tamron" />
    131
    +              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
    132
    +            </PATH_ELEMENT>
    133
    +            <PATH_ELEMENT>
    134
    +              <option name="myItemId" value="tamron" />
    135
    +              <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
    136
    +            </PATH_ELEMENT>
    137
    +          </PATH>
    138
    +        </subPane>
    139
    +      </pane>
    140
    +    </panes>
    141
    +  </component>
    142
    +  <component name="PropertiesComponent">
    143
    +    <property name="last_opened_file_path" value="$PROJECT_DIR$" />
    144
    +    <property name="WebServerToolWindowFactoryState" value="false" />
    145
    +    <property name="js-jscs-nodeInterpreter" value="$USER_HOME$/.nvm/versions/node/v6.10.0/bin/node" />
    146
    +  </component>
    147
    +  <component name="RecentsManager">
    148
    +    <key name="CopyFile.RECENT_KEYS">
    149
    +      <recent name="$PROJECT_DIR$/page" />
    150
    +      <recent name="$PROJECT_DIR$/page/templates/page" />
    151
    +    </key>
    152
    +  </component>
    153
    +  <component name="RunManager" selected="Django server.tamron">
    154
    +    <configuration default="true" type="DjangoTestsConfigurationType" factoryName="Django tests">
    155
    +      <option name="INTERPRETER_OPTIONS" value="" />
    156
    +      <option name="PARENT_ENVS" value="true" />
    157
    +      <envs>
    158
    +        <env name="PYTHONUNBUFFERED" value="1" />
    159
    +      </envs>
    160
    +      <option name="SDK_HOME" value="" />
    161
    +      <option name="WORKING_DIRECTORY" value="" />
    162
    +      <option name="IS_MODULE_SDK" value="false" />
    163
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    164
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    165
    +      <module name="tamron" />
    166
    +      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
    167
    +      <option name="TARGET" value="" />
    168
    +      <option name="SETTINGS_FILE" value="" />
    169
    +      <option name="CUSTOM_SETTINGS" value="false" />
    170
    +      <option name="USE_OPTIONS" value="false" />
    171
    +      <option name="OPTIONS" value="" />
    172
    +      <method />
    173
    +    </configuration>
    174
    +    <configuration default="true" type="JavascriptDebugType" factoryName="JavaScript Debug">
    175
    +      <method />
    176
    +    </configuration>
    177
    +    <configuration default="true" type="PyBehaveRunConfigurationType" factoryName="Behave">
    178
    +      <option name="INTERPRETER_OPTIONS" value="" />
    179
    +      <option name="PARENT_ENVS" value="true" />
    180
    +      <envs />
    181
    +      <option name="SDK_HOME" value="" />
    182
    +      <option name="WORKING_DIRECTORY" value="" />
    183
    +      <option name="IS_MODULE_SDK" value="false" />
    184
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    185
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    186
    +      <module name="tamron" />
    187
    +      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
    188
    +      <option name="ADDITIONAL_ARGS" value="" />
    189
    +      <method />
    190
    +    </configuration>
    191
    +    <configuration default="true" type="PyLettuceRunConfigurationType" factoryName="Lettuce">
    192
    +      <option name="INTERPRETER_OPTIONS" value="" />
    193
    +      <option name="PARENT_ENVS" value="true" />
    194
    +      <envs />
    195
    +      <option name="SDK_HOME" value="" />
    196
    +      <option name="WORKING_DIRECTORY" value="" />
    197
    +      <option name="IS_MODULE_SDK" value="false" />
    198
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    199
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    200
    +      <module name="tamron" />
    201
    +      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
    202
    +      <option name="ADDITIONAL_ARGS" value="" />
    203
    +      <method />
    204
    +    </configuration>
    205
    +    <configuration default="true" type="Python.DjangoServer" factoryName="Django server">
    206
    +      <option name="INTERPRETER_OPTIONS" value="" />
    207
    +      <option name="PARENT_ENVS" value="true" />
    208
    +      <envs>
    209
    +        <env name="PYTHONUNBUFFERED" value="1" />
    210
    +      </envs>
    211
    +      <option name="SDK_HOME" value="" />
    212
    +      <option name="WORKING_DIRECTORY" value="" />
    213
    +      <option name="IS_MODULE_SDK" value="false" />
    214
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    215
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    216
    +      <module name="tamron" />
    217
    +      <option name="launchJavascriptDebuger" value="false" />
    218
    +      <option name="port" value="8000" />
    219
    +      <option name="host" value="" />
    220
    +      <option name="additionalOptions" value="" />
    221
    +      <option name="browserUrl" value="" />
    222
    +      <option name="runTestServer" value="false" />
    223
    +      <option name="runNoReload" value="false" />
    224
    +      <option name="useCustomRunCommand" value="false" />
    225
    +      <option name="customRunCommand" value="" />
    226
    +      <method />
    227
    +    </configuration>
    228
    +    <configuration default="true" type="PythonConfigurationType" factoryName="Python">
    229
    +      <option name="INTERPRETER_OPTIONS" value="" />
    230
    +      <option name="PARENT_ENVS" value="true" />
    231
    +      <envs>
    232
    +        <env name="PYTHONUNBUFFERED" value="1" />
    233
    +      </envs>
    234
    +      <option name="SDK_HOME" value="" />
    235
    +      <option name="WORKING_DIRECTORY" value="" />
    236
    +      <option name="IS_MODULE_SDK" value="false" />
    237
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    238
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    239
    +      <module name="tamron" />
    240
    +      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
    241
    +      <option name="SCRIPT_NAME" value="" />
    242
    +      <option name="PARAMETERS" value="" />
    243
    +      <option name="SHOW_COMMAND_LINE" value="false" />
    244
    +      <method />
    245
    +    </configuration>
    246
    +    <configuration default="true" type="Tox" factoryName="Tox">
    247
    +      <option name="INTERPRETER_OPTIONS" value="" />
    248
    +      <option name="PARENT_ENVS" value="true" />
    249
    +      <envs />
    250
    +      <option name="SDK_HOME" value="" />
    251
    +      <option name="WORKING_DIRECTORY" value="" />
    252
    +      <option name="IS_MODULE_SDK" value="false" />
    253
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    254
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    255
    +      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
    256
    +      <module name="tamron" />
    257
    +      <method />
    258
    +    </configuration>
    259
    +    <configuration default="true" type="js.build_tools.gulp" factoryName="Gulp.js">
    260
    +      <node-interpreter>project</node-interpreter>
    261
    +      <node-options />
    262
    +      <gulpfile />
    263
    +      <tasks />
    264
    +      <arguments />
    265
    +      <envs />
    266
    +      <method />
    267
    +    </configuration>
    268
    +    <configuration default="true" type="js.build_tools.npm" factoryName="npm">
    269
    +      <command value="run-script" />
    270
    +      <scripts />
    271
    +      <node-interpreter value="project" />
    272
    +      <envs />
    273
    +      <method />
    274
    +    </configuration>
    275
    +    <configuration default="true" type="tests" factoryName="Attests">
    276
    +      <option name="INTERPRETER_OPTIONS" value="" />
    277
    +      <option name="PARENT_ENVS" value="true" />
    278
    +      <envs />
    279
    +      <option name="SDK_HOME" value="" />
    280
    +      <option name="WORKING_DIRECTORY" value="" />
    281
    +      <option name="IS_MODULE_SDK" value="false" />
    282
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    283
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    284
    +      <module name="tamron" />
    285
    +      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
    286
    +      <option name="SCRIPT_NAME" value="" />
    287
    +      <option name="CLASS_NAME" value="" />
    288
    +      <option name="METHOD_NAME" value="" />
    289
    +      <option name="FOLDER_NAME" value="" />
    290
    +      <option name="TEST_TYPE" value="TEST_SCRIPT" />
    291
    +      <option name="PATTERN" value="" />
    292
    +      <option name="USE_PATTERN" value="false" />
    293
    +      <method />
    294
    +    </configuration>
    295
    +    <configuration default="true" type="tests" factoryName="Doctests">
    296
    +      <option name="INTERPRETER_OPTIONS" value="" />
    297
    +      <option name="PARENT_ENVS" value="true" />
    298
    +      <envs />
    299
    +      <option name="SDK_HOME" value="" />
    300
    +      <option name="WORKING_DIRECTORY" value="" />
    301
    +      <option name="IS_MODULE_SDK" value="false" />
    302
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    303
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    304
    +      <module name="tamron" />
    305
    +      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
    306
    +      <option name="SCRIPT_NAME" value="" />
    307
    +      <option name="CLASS_NAME" value="" />
    308
    +      <option name="METHOD_NAME" value="" />
    309
    +      <option name="FOLDER_NAME" value="" />
    310
    +      <option name="TEST_TYPE" value="TEST_SCRIPT" />
    311
    +      <option name="PATTERN" value="" />
    312
    +      <option name="USE_PATTERN" value="false" />
    313
    +      <method />
    314
    +    </configuration>
    315
    +    <configuration default="true" type="tests" factoryName="Nosetests">
    316
    +      <option name="INTERPRETER_OPTIONS" value="" />
    317
    +      <option name="PARENT_ENVS" value="true" />
    318
    +      <envs />
    319
    +      <option name="SDK_HOME" value="" />
    320
    +      <option name="WORKING_DIRECTORY" value="" />
    321
    +      <option name="IS_MODULE_SDK" value="false" />
    322
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    323
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    324
    +      <module name="tamron" />
    325
    +      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
    326
    +      <option name="SCRIPT_NAME" value="" />
    327
    +      <option name="CLASS_NAME" value="" />
    328
    +      <option name="METHOD_NAME" value="" />
    329
    +      <option name="FOLDER_NAME" value="" />
    330
    +      <option name="TEST_TYPE" value="TEST_SCRIPT" />
    331
    +      <option name="PATTERN" value="" />
    332
    +      <option name="USE_PATTERN" value="false" />
    333
    +      <option name="PARAMS" value="" />
    334
    +      <option name="USE_PARAM" value="false" />
    335
    +      <method />
    336
    +    </configuration>
    337
    +    <configuration default="true" type="tests" factoryName="Unittests">
    338
    +      <option name="INTERPRETER_OPTIONS" value="" />
    339
    +      <option name="PARENT_ENVS" value="true" />
    340
    +      <envs />
    341
    +      <option name="SDK_HOME" value="" />
    342
    +      <option name="WORKING_DIRECTORY" value="" />
    343
    +      <option name="IS_MODULE_SDK" value="false" />
    344
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    345
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    346
    +      <module name="tamron" />
    347
    +      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
    348
    +      <option name="SCRIPT_NAME" value="" />
    349
    +      <option name="CLASS_NAME" value="" />
    350
    +      <option name="METHOD_NAME" value="" />
    351
    +      <option name="FOLDER_NAME" value="" />
    352
    +      <option name="TEST_TYPE" value="TEST_SCRIPT" />
    353
    +      <option name="PATTERN" value="" />
    354
    +      <option name="USE_PATTERN" value="false" />
    355
    +      <option name="PUREUNITTEST" value="true" />
    356
    +      <option name="PARAMS" value="" />
    357
    +      <option name="USE_PARAM" value="false" />
    358
    +      <method />
    359
    +    </configuration>
    360
    +    <configuration default="true" type="tests" factoryName="py.test">
    361
    +      <option name="INTERPRETER_OPTIONS" value="" />
    362
    +      <option name="PARENT_ENVS" value="true" />
    363
    +      <envs />
    364
    +      <option name="SDK_HOME" value="" />
    365
    +      <option name="WORKING_DIRECTORY" value="" />
    366
    +      <option name="IS_MODULE_SDK" value="false" />
    367
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    368
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    369
    +      <module name="tamron" />
    370
    +      <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" />
    371
    +      <option name="SCRIPT_NAME" value="" />
    372
    +      <option name="CLASS_NAME" value="" />
    373
    +      <option name="METHOD_NAME" value="" />
    374
    +      <option name="FOLDER_NAME" value="" />
    375
    +      <option name="TEST_TYPE" value="TEST_SCRIPT" />
    376
    +      <option name="PATTERN" value="" />
    377
    +      <option name="USE_PATTERN" value="false" />
    378
    +      <option name="testToRun" value="" />
    379
    +      <option name="keywords" value="" />
    380
    +      <option name="params" value="" />
    381
    +      <option name="USE_PARAM" value="false" />
    382
    +      <option name="USE_KEYWORD" value="false" />
    383
    +      <method />
    384
    +    </configuration>
    385
    +    <configuration default="false" name="tamron" type="Python.DjangoServer" factoryName="Django server">
    386
    +      <option name="INTERPRETER_OPTIONS" value="" />
    387
    +      <option name="PARENT_ENVS" value="true" />
    388
    +      <envs>
    389
    +        <env name="PYTHONUNBUFFERED" value="1" />
    390
    +      </envs>
    391
    +      <option name="SDK_HOME" value="" />
    392
    +      <option name="WORKING_DIRECTORY" value="" />
    393
    +      <option name="IS_MODULE_SDK" value="false" />
    394
    +      <option name="ADD_CONTENT_ROOTS" value="true" />
    395
    +      <option name="ADD_SOURCE_ROOTS" value="true" />
    396
    +      <module name="tamron" />
    397
    +      <option name="launchJavascriptDebuger" value="false" />
    398
    +      <option name="port" value="8000" />
    399
    +      <option name="host" value="" />
    400
    +      <option name="additionalOptions" value="" />
    401
    +      <option name="browserUrl" value="" />
    402
    +      <option name="runTestServer" value="false" />
    403
    +      <option name="runNoReload" value="false" />
    404
    +      <option name="useCustomRunCommand" value="false" />
    405
    +      <option name="customRunCommand" value="" />
    406
    +      <method />
    407
    +    </configuration>
    408
    +    <list size="1">
    409
    +      <item index="0" class="java.lang.String" itemvalue="Django server.tamron" />
    410
    +    </list>
    411
    +  </component>
    412
    +  <component name="ShelveChangesManager" show_recycled="false">
    413
    +    <option name="remove_strategy" value="false" />
    414
    +  </component>
    415
    +  <component name="TaskManager">
    416
    +    <task active="true" id="Default" summary="Default task">
    417
    +      <changelist id="8287082c-5144-4790-9da1-578e292318f7" name="Default" comment="" />
    418
    +      <created>1497849391019</created>
    419
    +      <option name="number" value="Default" />
    420
    +      <option name="presentableId" value="Default" />
    421
    +      <updated>1497849391019</updated>
    422
    +    </task>
    423
    +    <servers />
    424
    +  </component>
    425
    +  <component name="ToolWindowManager">
    426
    +    <frame x="65" y="24" width="1301" height="744" extended-state="6" />
    427
    +    <editor active="false" />
    428
    +    <layout>
    429
    +      <window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.16756341" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
    430
    +      <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
    431
    +      <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
    432
    +      <window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
    433
    +      <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
    434
    +      <window_info id="Python Console" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
    435
    +      <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
    436
    +      <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
    437
    +      <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
    438
    +      <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
    439
    +      <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
    440
    +      <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
    441
    +      <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
    442
    +      <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
    443
    +      <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
    444
    +      <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
    445
    +      <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
    446
    +      <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
    447
    +    </layout>
    448
    +  </component>
    449
    +  <component name="Vcs.Log.UiProperties">
    450
    +    <option name="RECENTLY_FILTERED_USER_GROUPS">
    451
    +      <collection />
    452
    +    </option>
    453
    +    <option name="RECENTLY_FILTERED_BRANCH_GROUPS">
    454
    +      <collection />
    455
    +    </option>
    456
    +  </component>
    457
    +  <component name="VcsContentAnnotationSettings">
    458
    +    <option name="myLimit" value="2678400000" />
    459
    +  </component>
    460
    +  <component name="XDebuggerManager">
    461
    +    <breakpoint-manager>
    462
    +      <option name="time" value="2" />
    463
    +    </breakpoint-manager>
    464
    +    <watches-manager />
    465
    +  </component>
    466
    +  <component name="editorHistoryManager">
    467
    +    <entry file="file://$PROJECT_DIR$/page/models.py">
    468
    +      <provider selected="true" editor-type-id="text-editor">
    469
    +        <state relative-caret-position="0">
    470
    +          <caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
    471
    +        </state>
    472
    +      </provider>
    473
    +    </entry>
    474
    +    <entry file="file://$PROJECT_DIR$/account/admin.py">
    475
    +      <provider selected="true" editor-type-id="text-editor">
    476
    +        <state relative-caret-position="165">
    477
    +          <caret line="13" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="23" selection-end-column="0" />
    478
    +        </state>
    479
    +      </provider>
    480
    +    </entry>
    481
    +    <entry file="file://$PROJECT_DIR$/tamron/basemodels.py">
    482
    +      <provider selected="true" editor-type-id="text-editor">
    483
    +        <state relative-caret-position="105">
    484
    +          <caret line="7" column="94" selection-start-line="7" selection-start-column="79" selection-end-line="7" selection-end-column="94" />
    485
    +        </state>
    486
    +      </provider>
    487
    +    </entry>
    488
    +    <entry file="file://$PROJECT_DIR$/integral/admin.py">
    489
    +      <provider selected="true" editor-type-id="text-editor">
    490
    +        <state relative-caret-position="150">
    491
    +          <caret line="10" column="38" selection-start-line="10" selection-start-column="38" selection-end-line="10" selection-end-column="38" />
    492
    +        </state>
    493
    +      </provider>
    494
    +    </entry>
    495
    +    <entry file="file://$PROJECT_DIR$/product/admin.py">
    496
    +      <provider selected="true" editor-type-id="text-editor">
    497
    +        <state relative-caret-position="390">
    498
    +          <caret line="26" column="0" selection-start-line="26" selection-start-column="0" selection-end-line="26" selection-end-column="60" />
    499
    +        </state>
    500
    +      </provider>
    501
    +    </entry>
    502
    +    <entry file="file://$PROJECT_DIR$/integral/views.py">
    503
    +      <provider selected="true" editor-type-id="text-editor">
    504
    +        <state relative-caret-position="60">
    505
    +          <caret line="4" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="4" selection-end-column="0" />
    506
    +        </state>
    507
    +      </provider>
    508
    +    </entry>
    509
    +    <entry file="file://$PROJECT_DIR$/page/views.py">
    510
    +      <provider selected="true" editor-type-id="text-editor">
    511
    +        <state relative-caret-position="60">
    512
    +          <caret line="4" column="0" selection-start-line="4" selection-start-column="0" selection-end-line="4" selection-end-column="0" />
    513
    +        </state>
    514
    +      </provider>
    515
    +    </entry>
    516
    +    <entry file="file://$PROJECT_DIR$/product/models.py">
    517
    +      <provider selected="true" editor-type-id="text-editor">
    518
    +        <state relative-caret-position="308">
    519
    +          <caret line="43" column="104" selection-start-line="43" selection-start-column="104" selection-end-line="43" selection-end-column="104" />
    520
    +        </state>
    521
    +      </provider>
    522
    +    </entry>
    523
    +    <entry file="file://$PROJECT_DIR$/integral/models.py">
    524
    +      <provider selected="true" editor-type-id="text-editor">
    525
    +        <state relative-caret-position="360">
    526
    +          <caret line="24" column="30" selection-start-line="24" selection-start-column="30" selection-end-line="24" selection-end-column="30" />
    527
    +        </state>
    528
    +      </provider>
    529
    +    </entry>
    530
    +    <entry file="file://$PROJECT_DIR$/tamron/settings.py">
    531
    +      <provider selected="true" editor-type-id="text-editor">
    532
    +        <state relative-caret-position="312">
    533
    +          <caret line="200" column="6" selection-start-line="200" selection-start-column="0" selection-end-line="200" selection-end-column="6" />
    534
    +          <folding />
    535
    +        </state>
    536
    +      </provider>
    537
    +    </entry>
    538
    +    <entry file="file://$PROJECT_DIR$/tamron/local_settings.py">
    539
    +      <provider selected="true" editor-type-id="text-editor">
    540
    +        <state relative-caret-position="420">
    541
    +          <caret line="28" column="32" selection-start-line="28" selection-start-column="32" selection-end-line="28" selection-end-column="32" />
    542
    +        </state>
    543
    +      </provider>
    544
    +    </entry>
    545
    +    <entry file="file://$PROJECT_DIR$/api/urls.py">
    546
    +      <provider selected="true" editor-type-id="text-editor">
    547
    +        <state relative-caret-position="120">
    548
    +          <caret line="8" column="44" selection-start-line="8" selection-start-column="44" selection-end-line="8" selection-end-column="44" />
    549
    +        </state>
    550
    +      </provider>
    551
    +    </entry>
    552
    +    <entry file="file://$PROJECT_DIR$/page/templates/page/clerk_oauth.html">
    553
    +      <provider selected="true" editor-type-id="text-editor">
    554
    +        <state relative-caret-position="360">
    555
    +          <caret line="57" column="18" selection-start-line="25" selection-start-column="12" selection-end-line="57" selection-end-column="18" />
    556
    +          <folding />
    557
    +        </state>
    558
    +      </provider>
    559
    +    </entry>
    560
    +    <entry file="file://$PROJECT_DIR$/page/templates/page/clerk_sale.html">
    561
    +      <provider selected="true" editor-type-id="text-editor">
    562
    +        <state relative-caret-position="273">
    563
    +          <caret line="160" column="0" selection-start-line="160" selection-start-column="0" selection-end-line="160" selection-end-column="0" />
    564
    +          <folding />
    565
    +        </state>
    566
    +      </provider>
    567
    +    </entry>
    568
    +    <entry file="file://$PROJECT_DIR$/utils/error/errno_utils.py">
    569
    +      <provider selected="true" editor-type-id="text-editor">
    570
    +        <state relative-caret-position="75">
    571
    +          <caret line="5" column="26" selection-start-line="5" selection-start-column="6" selection-end-line="5" selection-end-column="26" />
    572
    +        </state>
    573
    +      </provider>
    574
    +    </entry>
    575
    +    <entry file="file://$PROJECT_DIR$/account/models.py">
    576
    +      <provider selected="true" editor-type-id="text-editor">
    577
    +        <state relative-caret-position="521">
    578
    +          <caret line="88" column="38" selection-start-line="88" selection-start-column="38" selection-end-line="88" selection-end-column="38" />
    579
    +        </state>
    580
    +      </provider>
    581
    +    </entry>
    582
    +    <entry file="file://$PROJECT_DIR$/tamron/urls.py">
    583
    +      <provider selected="true" editor-type-id="text-editor">
    584
    +        <state relative-caret-position="465">
    585
    +          <caret line="31" column="55" selection-start-line="31" selection-start-column="55" selection-end-line="31" selection-end-column="55" />
    586
    +        </state>
    587
    +      </provider>
    588
    +    </entry>
    589
    +    <entry file="file://$PROJECT_DIR$/page/sale_views.py">
    590
    +      <provider selected="true" editor-type-id="text-editor">
    591
    +        <state relative-caret-position="311">
    592
    +          <caret line="97" column="18" selection-start-line="97" selection-start-column="10" selection-end-line="97" selection-end-column="18" />
    593
    +        </state>
    594
    +      </provider>
    595
    +    </entry>
    596
    +    <entry file="file://$PROJECT_DIR$/page/info_views.py">
    597
    +      <provider selected="true" editor-type-id="text-editor">
    598
    +        <state relative-caret-position="300">
    599
    +          <caret line="20" column="42" selection-start-line="20" selection-start-column="42" selection-end-line="20" selection-end-column="42" />
    600
    +        </state>
    601
    +      </provider>
    602
    +    </entry>
    603
    +    <entry file="file://$PROJECT_DIR$/page/oauth_views.py">
    604
    +      <provider selected="true" editor-type-id="text-editor">
    605
    +        <state relative-caret-position="135">
    606
    +          <caret line="9" column="37" selection-start-line="9" selection-start-column="31" selection-end-line="9" selection-end-column="37" />
    607
    +        </state>
    608
    +      </provider>
    609
    +    </entry>
    610
    +    <entry file="file://$PROJECT_DIR$/page/templates/page/clerk_info.html">
    611
    +      <provider selected="true" editor-type-id="text-editor">
    612
    +        <state relative-caret-position="48">
    613
    +          <caret line="44" column="0" selection-start-line="44" selection-start-column="0" selection-end-line="44" selection-end-column="0" />
    614
    +        </state>
    615
    +      </provider>
    616
    +    </entry>
    617
    +    <entry file="file://$PROJECT_DIR$/tamron/uwsgi.bak/tamron.ini">
    618
    +      <provider selected="true" editor-type-id="text-editor">
    619
    +        <state relative-caret-position="255">
    620
    +          <caret line="17" column="61" selection-start-line="17" selection-start-column="61" selection-end-line="17" selection-end-column="61" />
    621
    +          <folding />
    622
    +        </state>
    623
    +      </provider>
    624
    +    </entry>
    625
    +    <entry file="file://$PROJECT_DIR$/tamron/uwsgi.bak/tamron_nginx.conf">
    626
    +      <provider selected="true" editor-type-id="text-editor">
    627
    +        <state relative-caret-position="480">
    628
    +          <caret line="32" column="50" selection-start-line="32" selection-start-column="50" selection-end-line="32" selection-end-column="50" />
    629
    +          <folding />
    630
    +        </state>
    631
    +      </provider>
    632
    +    </entry>
    633
    +  </component>
    634
    +</project>

    + 8 - 0
    .isort.cfg

    @@ -0,0 +1,8 @@
    1
    +# See the menu of settings available here:
    2
    +#   https://github.com/timothycrosley/isort/wiki/isort-Settings
    3
    +
    4
    +[settings]
    5
    +indent='    '
    6
    +line_length=120
    7
    +lines_after_imports=2
    8
    +skip=migrations

    + 0 - 0
    account/__init__.py


    BIN
    account/__init__.pyc


    + 23 - 0
    account/admin.py

    @@ -0,0 +1,23 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from django.contrib import admin
    4
    +
    5
    +from account.models import FranchiserInfo, SaleclerkInfo
    6
    +
    7
    +
    8
    +class FranchiserInfoAdmin(admin.ModelAdmin):
    9
    +    readonly_fields = ('franchiser_id', )
    10
    +    list_display = ('franchiser_id', 'franchiser_name', 'franchiser_addr', 'franchiser_phone', 'franchiser_boss_name', 'franchiser_boss_phone', 'status', 'created_at', 'updated_at')
    11
    +    search_fields = ('franchiser_id', 'franchiser_name', 'franchiser_addr', 'franchiser_phone', 'franchiser_boss_name', 'franchiser_boss_phone')
    12
    +    list_filter = ('status', )
    13
    +
    14
    +
    15
    +class SaleclerkInfoAdmin(admin.ModelAdmin):
    16
    +    readonly_fields = ('franchiser_id', )
    17
    +    list_display = ('franchiser_id', 'clerk_id', 'clerk_name', 'clerk_sex', 'clerk_phone', 'user_status', 'status', 'created_at', 'updated_at')
    18
    +    search_fields = ('franchiser_id', 'clerk_id', 'clerk_name', 'clerk_phone')
    19
    +    list_filter = ('user_status', 'status')
    20
    +
    21
    +
    22
    +admin.site.register(FranchiserInfo, FranchiserInfoAdmin)
    23
    +admin.site.register(SaleclerkInfo, SaleclerkInfoAdmin)

    BIN
    account/admin.pyc


    + 55 - 0
    account/migrations/0001_initial.py

    @@ -0,0 +1,55 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +from __future__ import unicode_literals
    3
    +
    4
    +from django.db import models, migrations
    5
    +import shortuuidfield.fields
    6
    +
    7
    +
    8
    +class Migration(migrations.Migration):
    9
    +
    10
    +    dependencies = [
    11
    +    ]
    12
    +
    13
    +    operations = [
    14
    +        migrations.CreateModel(
    15
    +            name='FranchiserInfo',
    16
    +            fields=[
    17
    +                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
    18
    +                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
    19
    +                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
    20
    +                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
    21
    +                ('franchiser_id', shortuuidfield.fields.ShortUUIDField(editable=False, max_length=22, blank=True, help_text='\u7ecf\u9500\u5546\u552f\u4e00\u6807\u8bc6', unique=True, db_index=True)),
    22
    +                ('franchiser_name', models.CharField(help_text='\u7ecf\u9500\u5546\u540d\u79f0', max_length=255, null=True, verbose_name='franchiser_name', blank=True)),
    23
    +                ('franchiser_addr', models.CharField(help_text='\u7ecf\u9500\u5546\u5730\u5740', max_length=255, null=True, verbose_name='franchiser_addr', blank=True)),
    24
    +                ('franchiser_phone', models.CharField(help_text='\u7ecf\u9500\u5546\u8054\u7cfb\u7535\u8bdd', max_length=255, null=True, verbose_name='franchiser_phone', blank=True)),
    25
    +                ('franchiser_boss_name', models.CharField(help_text='\u7ecf\u9500\u5546\u8001\u677f\u540d\u79f0', max_length=255, null=True, verbose_name='franchiser_boss_name', blank=True)),
    26
    +                ('franchiser_boss_phone', models.CharField(help_text='\u7ecf\u9500\u5546\u8001\u677f\u8054\u7cfb\u7535\u8bdd', max_length=255, null=True, verbose_name='franchiser_boss_phone', blank=True)),
    27
    +            ],
    28
    +            options={
    29
    +                'verbose_name': 'franchiserinfo',
    30
    +                'verbose_name_plural': 'franchiserinfo',
    31
    +            },
    32
    +        ),
    33
    +        migrations.CreateModel(
    34
    +            name='SaleclerkInfo',
    35
    +            fields=[
    36
    +                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
    37
    +                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
    38
    +                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
    39
    +                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
    40
    +                ('franchiser_id', models.CharField(max_length=255, blank=True, help_text='\u7ecf\u9500\u5546\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='franchiser_id', db_index=True)),
    41
    +                ('clerk_id', shortuuidfield.fields.ShortUUIDField(editable=False, max_length=22, blank=True, help_text='\u5e97\u5458\u552f\u4e00\u6807\u8bc6', unique=True, db_index=True)),
    42
    +                ('clerk_name', models.CharField(help_text='\u5e97\u5458\u540d\u79f0', max_length=255, null=True, verbose_name='clerk_name', blank=True)),
    43
    +                ('clerk_sex', models.IntegerField(default=1, help_text='\u5e97\u5458\u6027\u522b', verbose_name='clerk_sex', choices=[(1, '\u7537'), (0, '\u5973')])),
    44
    +                ('clerk_phone', models.CharField(help_text='\u5e97\u5458\u8054\u7cfb\u7535\u8bdd', max_length=255, null=True, verbose_name='clerk_phone', blank=True)),
    45
    +                ('openid', models.CharField(null=True, max_length=255, blank=True, help_text='\u5fae\u4fe1 OpenID', unique=True, verbose_name='openid', db_index=True)),
    46
    +                ('unionid', models.CharField(null=True, max_length=255, blank=True, help_text='\u5fae\u4fe1 UnionID', unique=True, verbose_name='unionid', db_index=True)),
    47
    +                ('user_status', models.IntegerField(default=0, verbose_name='user_status', choices=[(-1, '\u5df2\u62d2\u7edd'), (0, '\u672a\u9a8c\u8bc1'), (1, '\u5df2\u6fc0\u6d3b'), (2, '\u5df2\u7981\u7528'), (3, '\u5df2\u5220\u9664'), (10, '\u5df2\u5206\u914d')])),
    48
    +                ('refused_reason', models.TextField(help_text='\u5ba1\u6838\u62d2\u7edd\u539f\u56e0', null=True, verbose_name='refused_reason', blank=True)),
    49
    +            ],
    50
    +            options={
    51
    +                'verbose_name': 'saleclerkinfo',
    52
    +                'verbose_name_plural': 'saleclerkinfo',
    53
    +            },
    54
    +        ),
    55
    +    ]

    BIN
    account/migrations/0001_initial.pyc


    + 33 - 0
    account/migrations/0002_auto_20170619_1635.py

    @@ -0,0 +1,33 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +from __future__ import unicode_literals
    3
    +
    4
    +from django.db import models, migrations
    5
    +
    6
    +
    7
    +class Migration(migrations.Migration):
    8
    +
    9
    +    dependencies = [
    10
    +        ('account', '0001_initial'),
    11
    +    ]
    12
    +
    13
    +    operations = [
    14
    +        migrations.AlterModelOptions(
    15
    +            name='franchiserinfo',
    16
    +            options={'verbose_name': '\u7ecf\u9500\u5546\u4fe1\u606f\u8868', 'verbose_name_plural': '\u7ecf\u9500\u5546\u4fe1\u606f\u8868'},
    17
    +        ),
    18
    +        migrations.AddField(
    19
    +            model_name='saleclerkinfo',
    20
    +            name='integral',
    21
    +            field=models.IntegerField(default=0, help_text='\u79ef\u5206', verbose_name='integral'),
    22
    +        ),
    23
    +        migrations.AlterField(
    24
    +            model_name='saleclerkinfo',
    25
    +            name='clerk_sex',
    26
    +            field=models.IntegerField(default=1, help_text='\u5e97\u5458\u6027\u522b', db_index=True, verbose_name='clerk_sex', choices=[(1, '\u7537'), (0, '\u5973')]),
    27
    +        ),
    28
    +        migrations.AlterField(
    29
    +            model_name='saleclerkinfo',
    30
    +            name='user_status',
    31
    +            field=models.IntegerField(default=0, help_text='\u7528\u6237\u72b6\u6001', db_index=True, verbose_name='user_status', choices=[(-1, '\u5df2\u62d2\u7edd'), (0, '\u672a\u9a8c\u8bc1'), (1, '\u5df2\u6fc0\u6d3b'), (2, '\u5df2\u7981\u7528'), (3, '\u5df2\u5220\u9664'), (10, '\u5df2\u5206\u914d')]),
    32
    +        ),
    33
    +    ]

    BIN
    account/migrations/0002_auto_20170619_1635.pyc


    + 19 - 0
    account/migrations/0003_saleclerkinfo_franchiser_name.py

    @@ -0,0 +1,19 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +from __future__ import unicode_literals
    3
    +
    4
    +from django.db import models, migrations
    5
    +
    6
    +
    7
    +class Migration(migrations.Migration):
    8
    +
    9
    +    dependencies = [
    10
    +        ('account', '0002_auto_20170619_1635'),
    11
    +    ]
    12
    +
    13
    +    operations = [
    14
    +        migrations.AddField(
    15
    +            model_name='saleclerkinfo',
    16
    +            name='franchiser_name',
    17
    +            field=models.CharField(help_text='\u7ecf\u9500\u5546\u540d\u79f0', max_length=255, null=True, verbose_name='franchiser_name', blank=True),
    18
    +        ),
    19
    +    ]

    BIN
    account/migrations/0003_saleclerkinfo_franchiser_name.pyc


    + 0 - 0
    account/migrations/__init__.py


    BIN
    account/migrations/__init__.pyc


    + 92 - 0
    account/models.py

    @@ -0,0 +1,92 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from django.db import models
    4
    +from django.utils.translation import ugettext_lazy as _
    5
    +from shortuuidfield import ShortUUIDField
    6
    +
    7
    +from tamron.basemodels import CreateUpdateMixin
    8
    +
    9
    +
    10
    +class FranchiserInfo(CreateUpdateMixin):
    11
    +    franchiser_id = ShortUUIDField(_(u'franchiser_id'), max_length=255, help_text=u'经销商唯一标识', db_index=True, unique=True)
    12
    +    franchiser_name = models.CharField(_(u'franchiser_name'), max_length=255, blank=True, null=True, help_text=u'经销商名称')
    13
    +    franchiser_addr = models.CharField(_(u'franchiser_addr'), max_length=255, blank=True, null=True, help_text=u'经销商地址')
    14
    +    franchiser_phone = models.CharField(_(u'franchiser_phone'), max_length=255, blank=True, null=True, help_text=u'经销商联系电话')
    15
    +    franchiser_boss_name = models.CharField(_(u'franchiser_boss_name'), max_length=255, blank=True, null=True, help_text=u'经销商老板名称')
    16
    +    franchiser_boss_phone = models.CharField(_(u'franchiser_boss_phone'), max_length=255, blank=True, null=True, help_text=u'经销商老板联系电话')
    17
    +
    18
    +    class Meta:
    19
    +        verbose_name = _(u'经销商信息表')
    20
    +        verbose_name_plural = _(u'经销商信息表')
    21
    +
    22
    +    def __unicode__(self):
    23
    +        return unicode(self.pk)
    24
    +
    25
    +    @property
    26
    +    def data(self):
    27
    +        return {
    28
    +            'franchiser_id': self.franchiser_id,
    29
    +            'franchiser_name': self.franchiser_name,
    30
    +        }
    31
    +
    32
    +
    33
    +class SaleclerkInfo(CreateUpdateMixin):
    34
    +    MALE = 1
    35
    +    FEMALE = 0
    36
    +
    37
    +    SEX_TYPE = (
    38
    +        (MALE, u'男'),
    39
    +        (FEMALE, u'女'),
    40
    +    )
    41
    +
    42
    +    REFUSED = -1
    43
    +    UNVERIFIED = 0
    44
    +    ACTIVATED = 1
    45
    +    DISABLED = 2
    46
    +    DELETED = 3
    47
    +    ASSIGN = 10
    48
    +
    49
    +    USER_STATUS = (
    50
    +        (REFUSED, u'已拒绝'),
    51
    +        (UNVERIFIED, u'未验证'),
    52
    +        (ACTIVATED, u'已激活'),
    53
    +        (DISABLED, u'已禁用'),
    54
    +        (DELETED, u'已删除'),
    55
    +        (ASSIGN, u'已分配'),
    56
    +    )
    57
    +
    58
    +    franchiser_id = models.CharField(_(u'franchiser_id'), max_length=255, blank=True, null=True, help_text=u'经销商唯一标识', db_index=True)
    59
    +    franchiser_name = models.CharField(_(u'franchiser_name'), max_length=255, blank=True, null=True, help_text=u'经销商名称')
    60
    +    clerk_id = ShortUUIDField(_(u'clerk_id'), max_length=255, help_text=u'店员唯一标识', db_index=True, unique=True)
    61
    +    clerk_name = models.CharField(_(u'clerk_name'), max_length=255, blank=True, null=True, help_text=u'店员名称')
    62
    +    clerk_sex = models.IntegerField(_(u'clerk_sex'), choices=SEX_TYPE, default=MALE, help_text=u'店员性别', db_index=True)
    63
    +    clerk_phone = models.CharField(_(u'clerk_phone'), max_length=255, blank=True, null=True, help_text=u'店员联系电话')
    64
    +
    65
    +    openid = models.CharField(_(u'openid'), max_length=255, blank=True, null=True, help_text=u'微信 OpenID', db_index=True, unique=True)
    66
    +    unionid = models.CharField(_(u'unionid'), max_length=255, blank=True, null=True, help_text=u'微信 UnionID', db_index=True, unique=True)
    67
    +
    68
    +    integral = models.IntegerField(_(u'integral'), default=0, help_text=u'积分')
    69
    +
    70
    +    user_status = models.IntegerField(_(u'user_status'), choices=USER_STATUS, default=UNVERIFIED, help_text=u'用户状态', db_index=True)
    71
    +    refused_reason = models.TextField(_(u'refused_reason'), blank=True, null=True, help_text=u'审核拒绝原因')
    72
    +
    73
    +    class Meta:
    74
    +        verbose_name = _(u'saleclerkinfo')
    75
    +        verbose_name_plural = _(u'saleclerkinfo')
    76
    +
    77
    +    def __unicode__(self):
    78
    +        return unicode(self.pk)
    79
    +
    80
    +    @property
    81
    +    def data(self):
    82
    +        return {
    83
    +            'franchiser_id': self.franchiser_id,
    84
    +            'franchiser_name': self.franchiser_name,
    85
    +            'clerk_id': self.clerk_id,
    86
    +            'clerk_name': self.clerk_name,
    87
    +            'clerk_sex': self.clerk_sex,
    88
    +            'clerk_phone': self.clerk_phone,
    89
    +            'integral': self.integral,
    90
    +            'status': self.user_status,
    91
    +            'refused_reason': self.refused_reason,
    92
    +        }

    BIN
    account/models.pyc


    + 4 - 0
    account/tests.py

    @@ -0,0 +1,4 @@
    1
    +from django.test import TestCase
    2
    +
    3
    +
    4
    +# Create your tests here.

    + 4 - 0
    account/views.py

    @@ -0,0 +1,4 @@
    1
    +from django.shortcuts import render
    2
    +
    3
    +
    4
    +# Create your views here.

    + 0 - 0
    api/__init__.py


    BIN
    api/__init__.pyc


    + 4 - 0
    api/admin.py

    @@ -0,0 +1,4 @@
    1
    +from django.contrib import admin
    2
    +
    3
    +
    4
    +# Register your models here.

    BIN
    api/admin.pyc


    + 0 - 0
    api/migrations/__init__.py


    BIN
    api/migrations/__init__.pyc


    + 4 - 0
    api/models.py

    @@ -0,0 +1,4 @@
    1
    +from django.db import models
    2
    +
    3
    +
    4
    +# Create your models here.

    BIN
    api/models.pyc


    + 4 - 0
    api/tests.py

    @@ -0,0 +1,4 @@
    1
    +from django.test import TestCase
    2
    +
    3
    +
    4
    +# Create your tests here.

    + 11 - 0
    api/urls.py

    @@ -0,0 +1,11 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from django.conf.urls import url
    4
    +
    5
    +from page import oauth_views, sale_views
    6
    +
    7
    +
    8
    +urlpatterns = [
    9
    +    url(r'^clerk/submit$', oauth_views.clerk_submit_api, name='clerk_submit_api'),  # 店员信息提交
    10
    +    url(r'^clerk/sale/submit$', sale_views.clerk_sale_submit_api, name='clerk_sale_submit_api'),  # 店员销售信息提交
    11
    +]

    BIN
    api/urls.pyc


    + 4 - 0
    api/views.py

    @@ -0,0 +1,4 @@
    1
    +from django.shortcuts import render
    2
    +
    3
    +
    4
    +# Create your views here.

    + 9 - 0
    check.sh

    @@ -0,0 +1,9 @@
    1
    +#!/bin/bash
    2
    +
    3
    +echo '>> iSort'
    4
    +./isort.sh
    5
    +echo
    6
    +
    7
    +echo '>> PEP8'
    8
    +./pep8.sh
    9
    +echo

    + 0 - 0
    integral/__init__.py


    BIN
    integral/__init__.pyc


    + 15 - 0
    integral/admin.py

    @@ -0,0 +1,15 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from django.contrib import admin
    4
    +
    5
    +from integral.models import SaleclerkIntegralIncomeExpensesInfo
    6
    +
    7
    +
    8
    +class SaleclerkIntegralIncomeExpensesInfoAdmin(admin.ModelAdmin):
    9
    +    readonly_fields = ('franchiser_id', 'clerk_id', 'type', 'code', 'integral', 'left_integral')
    10
    +    list_display = ('franchiser_id', 'clerk_id', 'type', 'code', 'integral', 'left_integral', 'remark', 'status', 'created_at', 'updated_at')
    11
    +    search_fields = ('code', 'remark')
    12
    +    list_filter = ('franchiser_id', 'type', 'status')
    13
    +
    14
    +
    15
    +admin.site.register(SaleclerkIntegralIncomeExpensesInfo, SaleclerkIntegralIncomeExpensesInfoAdmin)

    BIN
    integral/admin.pyc


    + 33 - 0
    integral/migrations/0001_initial.py

    @@ -0,0 +1,33 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +from __future__ import unicode_literals
    3
    +
    4
    +from django.db import models, migrations
    5
    +
    6
    +
    7
    +class Migration(migrations.Migration):
    8
    +
    9
    +    dependencies = [
    10
    +    ]
    11
    +
    12
    +    operations = [
    13
    +        migrations.CreateModel(
    14
    +            name='SaleclerkIntegralIncomeExpensesInfo',
    15
    +            fields=[
    16
    +                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
    17
    +                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
    18
    +                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
    19
    +                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
    20
    +                ('franchiser_id', models.CharField(max_length=255, blank=True, help_text='\u7ecf\u9500\u5546\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='franchiser_id', db_index=True)),
    21
    +                ('clerk_id', models.CharField(max_length=255, blank=True, help_text='\u5e97\u5458\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='clerk_id', db_index=True)),
    22
    +                ('type', models.IntegerField(default=0, help_text='\u6536\u652f\u7c7b\u522b', db_index=True, verbose_name='type', choices=[(0, '\u6536\u5165'), (1, '\u652f\u51fa'), (2, '\u89e3\u51bb')])),
    23
    +                ('code', models.CharField(help_text='\u673a\u8eab\u7801', max_length=255, null=True, verbose_name='code', blank=True)),
    24
    +                ('integral', models.IntegerField(default=0, help_text='\u589e\u51cf\u79ef\u5206', verbose_name='integral')),
    25
    +                ('left_integral', models.IntegerField(default=0, help_text='\u79ef\u5206\u589e\u51cf\u540e\u6570\u91cf(\u5206)', verbose_name='left_integral')),
    26
    +                ('remark', models.CharField(help_text='\u5907\u6ce8', max_length=255, null=True, verbose_name='remark', blank=True)),
    27
    +            ],
    28
    +            options={
    29
    +                'verbose_name': 'saleclerkintegralincomeexpensesinfo',
    30
    +                'verbose_name_plural': 'saleclerkintegralincomeexpensesinfo',
    31
    +            },
    32
    +        ),
    33
    +    ]

    BIN
    integral/migrations/0001_initial.pyc


    + 19 - 0
    integral/migrations/0002_auto_20170619_1734.py

    @@ -0,0 +1,19 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +from __future__ import unicode_literals
    3
    +
    4
    +from django.db import models, migrations
    5
    +
    6
    +
    7
    +class Migration(migrations.Migration):
    8
    +
    9
    +    dependencies = [
    10
    +        ('integral', '0001_initial'),
    11
    +    ]
    12
    +
    13
    +    operations = [
    14
    +        migrations.AlterField(
    15
    +            model_name='saleclerkintegralincomeexpensesinfo',
    16
    +            name='code',
    17
    +            field=models.CharField(max_length=255, blank=True, help_text='\u673a\u8eab\u7801', null=True, verbose_name='code', db_index=True),
    18
    +        ),
    19
    +    ]

    BIN
    integral/migrations/0002_auto_20170619_1734.pyc


    + 0 - 0
    integral/migrations/__init__.py


    BIN
    integral/migrations/__init__.pyc


    + 36 - 0
    integral/models.py

    @@ -0,0 +1,36 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from django.db import models
    4
    +from django.utils.translation import ugettext_lazy as _
    5
    +
    6
    +from tamron.basemodels import CreateUpdateMixin
    7
    +
    8
    +
    9
    +class SaleclerkIntegralIncomeExpensesInfo(CreateUpdateMixin):
    10
    +    INCOME = 0
    11
    +    EXPENSE = 1
    12
    +    UNFREEZE = 2
    13
    +
    14
    +    TYPE = (
    15
    +        (INCOME, u'收入'),
    16
    +        (EXPENSE, u'支出'),
    17
    +        (UNFREEZE, u'解冻'),
    18
    +    )
    19
    +
    20
    +    franchiser_id = models.CharField(_(u'franchiser_id'), max_length=255, blank=True, null=True, help_text=u'经销商唯一标识', db_index=True)
    21
    +    clerk_id = models.CharField(_(u'clerk_id'), max_length=255, blank=True, null=True, help_text=u'店员唯一标识', db_index=True)
    22
    +
    23
    +    type = models.IntegerField(_(u'type'), choices=TYPE, default=INCOME, help_text=u'收支类别', db_index=True)
    24
    +
    25
    +    code = models.CharField(_(u'code'), max_length=255, blank=True, null=True, help_text=u'机身码', db_index=True)
    26
    +    integral = models.IntegerField(_(u'integral'), default=0, help_text=u'增减积分')
    27
    +    left_integral = models.IntegerField(_(u'left_integral'), default=0, help_text=u'积分增减后数量(分)')
    28
    +
    29
    +    remark = models.CharField(_(u'remark'), max_length=255, blank=True, null=True, help_text=u'备注')
    30
    +
    31
    +    class Meta:
    32
    +        verbose_name = _(u'saleclerkintegralincomeexpensesinfo')
    33
    +        verbose_name_plural = _(u'saleclerkintegralincomeexpensesinfo')
    34
    +
    35
    +    def __unicode__(self):
    36
    +        return unicode(self.pk)

    BIN
    integral/models.pyc


    + 4 - 0
    integral/tests.py

    @@ -0,0 +1,4 @@
    1
    +from django.test import TestCase
    2
    +
    3
    +
    4
    +# Create your tests here.

    + 4 - 0
    integral/views.py

    @@ -0,0 +1,4 @@
    1
    +from django.shortcuts import render
    2
    +
    3
    +
    4
    +# Create your views here.

    + 3 - 0
    isort.sh

    @@ -0,0 +1,3 @@
    1
    +#!/bin/bash
    2
    +
    3
    +isort -rc -sp . .

    + 11 - 0
    manage.py

    @@ -0,0 +1,11 @@
    1
    +#!/usr/bin/env python
    2
    +import os
    3
    +import sys
    4
    +
    5
    +
    6
    +if __name__ == "__main__":
    7
    +    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tamron.settings")
    8
    +
    9
    +    from django.core.management import execute_from_command_line
    10
    +
    11
    +    execute_from_command_line(sys.argv)

    + 0 - 0
    page/__init__.py


    BIN
    page/__init__.pyc


    + 4 - 0
    page/admin.py

    @@ -0,0 +1,4 @@
    1
    +from django.contrib import admin
    2
    +
    3
    +
    4
    +# Register your models here.

    BIN
    page/admin.pyc


    + 22 - 0
    page/info_views.py

    @@ -0,0 +1,22 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from __future__ import division
    4
    +
    5
    +from django.conf import settings
    6
    +from django.shortcuts import render
    7
    +
    8
    +from account.models import SaleclerkInfo
    9
    +
    10
    +
    11
    +def clerk_info_oauth(request):
    12
    +    unionid = request.GET.get('unionid', '')
    13
    +
    14
    +    try:
    15
    +        clerk = SaleclerkInfo.objects.get(unionid=unionid)
    16
    +    except SaleclerkInfo.DoesNotExist:
    17
    +        clerk = None
    18
    +
    19
    +    return render(request, 'page/clerk_info.html', {
    20
    +        'domain': settings.DOMAIN,
    21
    +        'clerk_info': clerk and clerk.data,
    22
    +    })

    BIN
    page/info_views.pyc


    + 0 - 0
    page/migrations/__init__.py


    BIN
    page/migrations/__init__.pyc


    + 4 - 0
    page/models.py

    @@ -0,0 +1,4 @@
    1
    +from django.db import models
    2
    +
    3
    +
    4
    +# Create your models here.

    BIN
    page/models.pyc


    + 70 - 0
    page/oauth_views.py

    @@ -0,0 +1,70 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from __future__ import division
    4
    +
    5
    +from django.conf import settings
    6
    +from django.db import transaction
    7
    +from django.shortcuts import render
    8
    +from logit import logit
    9
    +
    10
    +from account.models import FranchiserInfo, SaleclerkInfo
    11
    +from utils.error.errno_utils import FranchiserStatusCode, SaleclerkStatusCode
    12
    +from utils.error.response_utils import response
    13
    +
    14
    +
    15
    +def clerk_oauth(request):
    16
    +    unionid = request.GET.get('unionid', '')
    17
    +
    18
    +    chisers = FranchiserInfo.objects.filter(status=True)
    19
    +    chisers = [chiser.data for chiser in chisers]
    20
    +
    21
    +    try:
    22
    +        clerk = SaleclerkInfo.objects.get(unionid=unionid)
    23
    +    except SaleclerkInfo.DoesNotExist:
    24
    +        clerk = None
    25
    +
    26
    +    return render(request, 'page/clerk_oauth.html', {
    27
    +        'domain': settings.DOMAIN,
    28
    +        'chisers': chisers,
    29
    +        'clerk_info': clerk and clerk.data,
    30
    +        'modified': bool((not clerk) or (clerk and clerk.user_status in [SaleclerkInfo.UNVERIFIED, SaleclerkInfo.REFUSED])),  # 是否可以更改信息
    31
    +    })
    32
    +
    33
    +
    34
    +@logit
    35
    +@transaction.atomic
    36
    +def clerk_submit_api(request):
    37
    +    """ 店员授权信息提交 """
    38
    +    unionid = request.POST.get('unionid', '')
    39
    +    openid = request.POST.get('openid', '')
    40
    +    phone = request.POST.get('phone', '')
    41
    +    chiser = request.POST.get('chiser', '')
    42
    +
    43
    +    if SaleclerkInfo.objects.filter(clerk_phone=phone).exclude(unionid=unionid).exists():
    44
    +        return response(SaleclerkStatusCode.CLERK_PHONE_ALREADY_EXISTS)
    45
    +
    46
    +    try:
    47
    +        franchiser = FranchiserInfo.objects.get(franchiser_id=chiser)
    48
    +    except FranchiserInfo.DoesNotExist:
    49
    +        return response(FranchiserStatusCode.CHISER_NOT_FOUND)
    50
    +
    51
    +    fields = {
    52
    +        'franchiser_id': chiser,
    53
    +        'franchiser_name': franchiser.franchiser_name,
    54
    +        'clerk_name': request.POST.get('name', ''),
    55
    +        'clerk_sex': int(request.POST.get('sex', 1)),
    56
    +        'clerk_phone': phone,
    57
    +        'openid': openid,
    58
    +        'user_status': SaleclerkInfo.UNVERIFIED,
    59
    +    }
    60
    +
    61
    +    lensman, created = SaleclerkInfo.objects.select_for_update().get_or_create(unionid=unionid, defaults=fields)
    62
    +    # 状态为 UNVERIFIED 的允许修改, 其他需要登录摄影师 APP 进行信息的修改
    63
    +    if lensman.user_status not in [SaleclerkInfo.UNVERIFIED, SaleclerkInfo.REFUSED]:
    64
    +        return response(SaleclerkInfo.LENSMAN_ALREADY_NOT_UNVERIFIED)
    65
    +    if not created:
    66
    +        for key, value in fields.iteritems():
    67
    +            setattr(lensman, key, value)
    68
    +        lensman.save()
    69
    +
    70
    +    return response(200, 'Submit Success', u'提交成功', {})

    BIN
    page/oauth_views.pyc


    + 111 - 0
    page/sale_views.py

    @@ -0,0 +1,111 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from __future__ import division
    4
    +
    5
    +from django.conf import settings
    6
    +from django.db import transaction
    7
    +from django.shortcuts import render
    8
    +from logit import logit
    9
    +
    10
    +from account.models import SaleclerkInfo
    11
    +from integral.models import SaleclerkIntegralIncomeExpensesInfo
    12
    +from product.models import ProductCodeSubmitLogInfo, ProductInfo, ProductModelInfo
    13
    +from utils.error.errno_utils import ProductModelStatusCode, ProductStatusCode, SaleclerkStatusCode
    14
    +from utils.error.response_utils import response
    15
    +
    16
    +
    17
    +def clerk_sale_oauth(request):
    18
    +    unionid = request.GET.get('unionid', '')
    19
    +
    20
    +    models = ProductModelInfo.objects.filter(status=True)
    21
    +    models = [model.data for model in models]
    22
    +
    23
    +    try:
    24
    +        clerk = SaleclerkInfo.objects.get(unionid=unionid)
    25
    +    except SaleclerkInfo.DoesNotExist:
    26
    +        clerk = None
    27
    +
    28
    +    return render(request, 'page/clerk_sale.html', {
    29
    +        'domain': settings.DOMAIN,
    30
    +        'models': models,
    31
    +        'clerk_info': clerk and clerk.data,
    32
    +    })
    33
    +
    34
    +
    35
    +@logit
    36
    +@transaction.atomic
    37
    +def clerk_sale_submit_api(request):
    38
    +    """ 店员信息提交 """
    39
    +    clerk_id = request.POST.get('clerk_id', '')
    40
    +    model_id = request.POST.get('model_id', '')
    41
    +    code = request.POST.get('code', '')
    42
    +    name = request.POST.get('name', '')
    43
    +    sex = int(request.POST.get('sex', 1))
    44
    +    age = int(request.POST.get('age', 1))
    45
    +    phone = request.POST.get('phone', '')
    46
    +
    47
    +    # 店员是否存在
    48
    +    try:
    49
    +        clerk = SaleclerkInfo.objects.select_for_update().get(clerk_id=clerk_id)
    50
    +    except SaleclerkInfo.DoesNotExist:
    51
    +        return response(SaleclerkStatusCode.CLERK_NOT_FOUND)
    52
    +
    53
    +    # 店员是否激活
    54
    +    if clerk.user_status != SaleclerkInfo.ACTIVATED:
    55
    +        return response(SaleclerkStatusCode.CLERK_NOT_ACTIVATED)
    56
    +
    57
    +    # 型号是否存在
    58
    +    try:
    59
    +        model = ProductModelInfo.objects.get(model_id=model_id)
    60
    +    except ProductModelInfo.DoesNotExist:
    61
    +        return response(ProductModelStatusCode.MODEL_NOT_FOUND)
    62
    +
    63
    +    # 记录销售提交记录
    64
    +    ProductCodeSubmitLogInfo.objects.create(
    65
    +        model_id=model.model_id,
    66
    +        model_name=model.model_name,
    67
    +        code=code,
    68
    +        franchiser_id=clerk.franchiser_id,
    69
    +        clerk_id=clerk.clerk_id,
    70
    +        consumer_name=name,
    71
    +        consumer_sex=sex,
    72
    +        consumer_age=age,
    73
    +        consumer_phone=phone,
    74
    +    )
    75
    +
    76
    +    # 产品是否存在
    77
    +    try:
    78
    +        product = ProductInfo.objects.select_for_update().get(model_id=model_id, code=code)
    79
    +    except ProductInfo.DoesNotExist:
    80
    +        return response(ProductStatusCode.PRODUCT_NOT_FOUND)
    81
    +
    82
    +    # 产品是否使用
    83
    +    if product.code_status:
    84
    +        return response(ProductStatusCode.PRODUCT_HAS_USED)
    85
    +
    86
    +    # 产品使用
    87
    +    product.code_status = True
    88
    +    product.integral_status = True
    89
    +    product.franchiser_id = clerk.franchiser_id
    90
    +    product.clerk_id = clerk.clerk_id
    91
    +    product.consumer_name = name
    92
    +    product.consumer_sex = sex
    93
    +    product.consumer_age = age
    94
    +    product.consumer_phone = phone
    95
    +    product.save()
    96
    +
    97
    +    # 店员积分
    98
    +    clerk.integral += product.integral
    99
    +    clerk.save()
    100
    +
    101
    +    # 店员积分记录
    102
    +    SaleclerkIntegralIncomeExpensesInfo.objects.create(
    103
    +        franchiser_id=clerk.franchiser_id,
    104
    +        clerk_id=clerk.clerk_id,
    105
    +        type=SaleclerkIntegralIncomeExpensesInfo.INCOME,
    106
    +        code=code,
    107
    +        integral=product.integral,
    108
    +        left_integral=clerk.integral,
    109
    +    )
    110
    +
    111
    +    return response(200, 'Submit Success', u'提交成功', {})

    BIN
    page/sale_views.pyc


    + 74 - 0
    page/templates/page/clerk_info.html

    @@ -0,0 +1,74 @@
    1
    +{% load staticfiles %}
    2
    +
    3
    +<!DOCTYPE html>
    4
    +<html lang="zh-CN">
    5
    +    <head>
    6
    +        <meta charset="utf-8">
    7
    +        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    8
    +        <meta name="format-detection" content="telephone=no,email=no,address=no">
    9
    +        <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
    10
    +        <title>店员销售</title>
    11
    +
    12
    +        <link href="https://res.wx.qq.com/open/libs/weui/0.4.3/weui.min.css" rel="stylesheet" type="text/css" />
    13
    +
    14
    +        <style>
    15
    +            input:required:invalid {
    16
    +                color: #E64340;
    17
    +            }
    18
    +            input:required:valid {
    19
    +                color: rgb(0, 0, 0);
    20
    +            }
    21
    +        </style>
    22
    +    </head>
    23
    +    <body>
    24
    +        <div class="container" >
    25
    +            <div class="weui_cells_title">基本信息</div>
    26
    +            <div class="weui_cells weui_cells_form">
    27
    +                <div class="weui_cell">
    28
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">姓名</label></div>
    29
    +                    <div class="weui_cell_bd weui_cell_primary">
    30
    +                        <input id="chiser" class="weui_input" type="text" value="{{ clerk_info.franchiser_name }}" disabled>
    31
    +                    </div>
    32
    +                </div>
    33
    +                <div class="weui_cell">
    34
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">姓名</label></div>
    35
    +                    <div class="weui_cell_bd weui_cell_primary">
    36
    +                        <input id="name" class="weui_input" type="text" value="{{ clerk_info.clerk_name }}" disabled>
    37
    +                    </div>
    38
    +                </div>
    39
    +                <div class="weui_cell">
    40
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">姓名</label></div>
    41
    +                    <div class="weui_cell_bd weui_cell_primary">
    42
    +                        <input id="sex" class="weui_input" type="text" value="{% ifequal clerk_info.clerk_sex 1 %}男{% else %}女{% endifequal %}" disabled>
    43
    +                    </div>
    44
    +                </div>
    45
    +                <div class="weui_cell">
    46
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">手机号</label></div>
    47
    +                    <div class="weui_cell_bd weui_cell_primary">
    48
    +                        <input id="phone" class="weui_input" type="text" required="required" pattern="[0-9]{11}" value="{{ clerk_info.clerk_phone }}" disabled>
    49
    +                    </div>
    50
    +                </div>
    51
    +                <div class="weui_cell">
    52
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">积分</label></div>
    53
    +                    <div class="weui_cell_bd weui_cell_primary">
    54
    +                        <input id="integral" class="weui_input" type="text" required="required" pattern="[0-9]{11}" value="{{ clerk_info.integral }}" disabled>
    55
    +                    </div>
    56
    +                </div>
    57
    +            </div>
    58
    +        </div>
    59
    +
    60
    +        <script src="//cdn.bootcss.com/zepto/1.1.6/zepto.min.js"></script>
    61
    +        <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
    62
    +        <script type="text/javascript" src="{% static 'tamron/js/jswe.js' %}?v=1"></script>
    63
    +        <script>
    64
    +            V.initWxData({
    65
    +                imgUrl: "http://pai.ai/static/pai2/img/paiai_96_96.png",
    66
    +                link: 'http://api.pai.ai/wx_oauth2?redirect_url=http://pai.ai/page/lensman&scope=snsapi_base',
    67
    +                desc: "摄影师授权",
    68
    +                title: "摄影师授权",
    69
    +                timeLine: ""
    70
    +            }, true);
    71
    +            V.hideOptionMenu();
    72
    +        </script>
    73
    +    </body>
    74
    +</html>

    + 198 - 0
    page/templates/page/clerk_oauth.html

    @@ -0,0 +1,198 @@
    1
    +{% load staticfiles %}
    2
    +
    3
    +<!DOCTYPE html>
    4
    +<html lang="zh-CN">
    5
    +    <head>
    6
    +        <meta charset="utf-8">
    7
    +        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    8
    +        <meta name="format-detection" content="telephone=no,email=no,address=no">
    9
    +        <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
    10
    +        <title>店员授权</title>
    11
    +
    12
    +        <link href="https://res.wx.qq.com/open/libs/weui/0.4.3/weui.min.css" rel="stylesheet" type="text/css" />
    13
    +
    14
    +        <style>
    15
    +            input:required:invalid {
    16
    +                color: #E64340;
    17
    +            }
    18
    +            input:required:valid {
    19
    +                color: rgb(0, 0, 0);
    20
    +            }
    21
    +        </style>
    22
    +    </head>
    23
    +    <body>
    24
    +        <div class="container" >
    25
    +            <div class="weui_cells_title">基本信息</div>
    26
    +            <div class="weui_cells weui_cells_form">
    27
    +                <div class="weui_cell weui_cell_select weui_select_after">
    28
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">经销商</label></div>
    29
    +                    <div class="weui_cell_bd weui_cell_primary">
    30
    +                        <select id="chiser" class="weui_select" name="select" {% if not modified %}disabled{% endif %}>
    31
    +                            {% for chiser in chisers %}
    32
    +                            <option value="{{ chiser.franchiser_id }}" {% ifequal chiser.franchiser_id clerk_info.franchiser_id %}selected{% endifequal %}>{{ chiser.franchiser_name }}</option>
    33
    +                            {% endfor %}
    34
    +                        </select>
    35
    +                    </div>
    36
    +                </div>
    37
    +                <div class="weui_cell">
    38
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">姓名</label></div>
    39
    +                    <div class="weui_cell_bd weui_cell_primary">
    40
    +                        <input id="name" class="weui_input" type="text" value="{{ clerk_info.clerk_name }}" placeholder="请输入姓名" {% if not modified %}disabled{% endif %}>
    41
    +                    </div>
    42
    +                </div>
    43
    +                <div class="weui_cell weui_cell_select weui_select_after">
    44
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">性别</label></div>
    45
    +                    <div class="weui_cell_bd weui_cell_primary">
    46
    +                        <select id="sex" class="weui_select" name="select" {% if not modified %}disabled{% endif %}>
    47
    +                            <option value="1" {% ifequal clerk_info.clerk_sex 1 %}selected{% endifequal %}>男</option>
    48
    +                            <option value="0" {% ifequal clerk_info.clerk_sex 0 %}selected{% endifequal %}>女</option>
    49
    +                        </select>
    50
    +                    </div>
    51
    +                </div>
    52
    +                <div class="weui_cell">
    53
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">手机号</label></div>
    54
    +                    <div class="weui_cell_bd weui_cell_primary">
    55
    +                        <input id="phone" class="weui_input" type="text" required="required" pattern="[0-9]{11}" value="{{ clerk_info.clerk_phone }}" placeholder="请输入手机号" {% if not modified %}disabled{% endif %}>
    56
    +                    </div>
    57
    +                </div>
    58
    +            </div>
    59
    +
    60
    +            {% if clerk_info %}
    61
    +            <div class="weui_cells_title">审核状态</div>
    62
    +            <div class="weui_cells">
    63
    +                <div class="weui_cell">
    64
    +                    <div class="weui_cell_bd weui_cell_primary">
    65
    +                        <p>状态</p>
    66
    +                    </div>
    67
    +                    <div class="weui_cell_ft">
    68
    +                        {% ifequal clerk_info.status -1 %}已拒绝{% endifequal %}
    69
    +                        {% ifequal clerk_info.status 0 %}审核中{% endifequal %}
    70
    +                        {% ifequal clerk_info.status 1 %}已激活{% endifequal %}
    71
    +                        {% ifequal clerk_info.status 2 %}已禁用{% endifequal %}
    72
    +                        {% ifequal clerk_info.status 3 %}已删除{% endifequal %}
    73
    +                    </div>
    74
    +                </div>
    75
    +            </div>
    76
    +            {% endif %}
    77
    +
    78
    +
    79
    +            {% ifequal clerk_info.status -1 %}
    80
    +            <div class="weui_cells_title">拒绝原因</div>
    81
    +            <div class="weui_cells">
    82
    +                <div class="weui_panel_bd">
    83
    +                    <div class="weui_media_box weui_media_text">
    84
    +                        <p class="weui_media_desc">{{ clerk_info.refused_reason|safe|linebreaks }}</p>
    85
    +                    </div>
    86
    +                </div>
    87
    +            </div>
    88
    +            {% endifequal %}
    89
    +
    90
    +            <br>
    91
    +
    92
    +            {% if modified %}<button id="submit" class="weui_btn weui_btn_warn">确认</button>{% endif %}
    93
    +
    94
    +            <div class="weui_dialog_alert" id="dialog" style="display: none">
    95
    +                <div class="weui_mask"></div>
    96
    +                <div class="weui_dialog">
    97
    +                    <div class="weui_dialog_hd"><strong id="title" class="weui_dialog_title">弹窗标题</strong></div>
    98
    +                    <div id="content" class="weui_dialog_bd">弹窗内容,告知当前页面信息等</div>
    99
    +                    <div class="weui_dialog_ft">
    100
    +                        <a href="javascript:;" class="weui_btn_dialog primary">确定</a>
    101
    +                    </div>
    102
    +                </div>
    103
    +            </div>
    104
    +
    105
    +            <div id="toast" style="display: none;">
    106
    +                <div class="weui_mask_transparent"></div>
    107
    +                <div class="weui_toast">
    108
    +                    <i class="weui_icon_toast"></i>
    109
    +                    <p class="weui_toast_content">已完成</p>
    110
    +                </div>
    111
    +            </div>
    112
    +        </div>
    113
    +
    114
    +        <script src="//cdn.bootcss.com/zepto/1.1.6/zepto.min.js"></script>
    115
    +        <script>
    116
    +            {% if modified %}
    117
    +            $(function() {
    118
    +                function getURLParameter(name) {
    119
    +                  return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [null, ''])[1].replace(/\+/g, '%20')) || null;
    120
    +                }
    121
    +
    122
    +                function show_error_dialog(title, content) {
    123
    +                    $('#dialog #title').text(title);
    124
    +                    $('#dialog #content').text(content);
    125
    +                    $('#dialog').show();
    126
    +                }
    127
    +
    128
    +                function data_check() {
    129
    +                    var unionid = getURLParameter('unionid');
    130
    +                    if (!unionid) {
    131
    +                        show_error_dialog('微信授权', '微信授权失败,请重新打开页面');
    132
    +                        return false;
    133
    +                    }
    134
    +
    135
    +                    var name = $('#name').val();
    136
    +                    if (!name) {
    137
    +                        show_error_dialog('姓名', '姓名错误,请检查重新输入');
    138
    +                        return false;
    139
    +                    }
    140
    +
    141
    +                    var phone_valid = $('#phone').is(':valid');
    142
    +                    if (!phone_valid) {
    143
    +                        show_error_dialog('手机号', '手机号错误,请检查重新输入');
    144
    +                        return false;
    145
    +                    }
    146
    +
    147
    +                    return {
    148
    +                        unionid: unionid,
    149
    +                        openid: getURLParameter('openid'),
    150
    +                        chiser: $('#chiser option:checked').val(),
    151
    +                        name: name,
    152
    +                        sex: $('#sex option:checked').val(),
    153
    +                        phone: $('#phone').val(),
    154
    +                    }
    155
    +                }
    156
    +
    157
    +                $('#submit').click(function () {
    158
    +                    var check_result = data_check();
    159
    +                    if (check_result){
    160
    +                        $.ajax({
    161
    +                            type: 'POST',
    162
    +                            url: '{{ domain }}api/clerk/submit',
    163
    +                            data: check_result,
    164
    +                            success: function(data) {
    165
    +                                if (data.status == 200) {
    166
    +                                    $('#toast').show();
    167
    +                                    setTimeout(function () {
    168
    +                                        $('#toast').hide();
    169
    +                                    }, 1000);
    170
    +                                    window.location.reload();
    171
    +                                } else {
    172
    +                                    show_error_dialog('错误', data.description);
    173
    +                                }
    174
    +                            }
    175
    +                        })
    176
    +                    }
    177
    +                });
    178
    +
    179
    +                $('#dialog .weui_btn_dialog').click(function () {
    180
    +                    $('#dialog').hide();
    181
    +                })
    182
    +            });
    183
    +            {% endif %}
    184
    +        </script>
    185
    +        <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
    186
    +        <script type="text/javascript" src="{% static 'tamron/js/jswe.js' %}?v=1"></script>
    187
    +        <script>
    188
    +            V.initWxData({
    189
    +                imgUrl: "http://pai.ai/static/pai2/img/paiai_96_96.png",
    190
    +                link: 'http://api.pai.ai/wx_oauth2?redirect_url=http://pai.ai/page/lensman&scope=snsapi_base',
    191
    +                desc: "摄影师授权",
    192
    +                title: "摄影师授权",
    193
    +                timeLine: ""
    194
    +            }, true);
    195
    +            V.hideOptionMenu();
    196
    +        </script>
    197
    +    </body>
    198
    +</html>

    + 187 - 0
    page/templates/page/clerk_sale.html

    @@ -0,0 +1,187 @@
    1
    +{% load staticfiles %}
    2
    +
    3
    +<!DOCTYPE html>
    4
    +<html lang="zh-CN">
    5
    +    <head>
    6
    +        <meta charset="utf-8">
    7
    +        <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    8
    +        <meta name="format-detection" content="telephone=no,email=no,address=no">
    9
    +        <meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
    10
    +        <title>店员销售</title>
    11
    +
    12
    +        <link href="https://res.wx.qq.com/open/libs/weui/0.4.3/weui.min.css" rel="stylesheet" type="text/css" />
    13
    +
    14
    +        <style>
    15
    +            input:required:invalid {
    16
    +                color: #E64340;
    17
    +            }
    18
    +            input:required:valid {
    19
    +                color: rgb(0, 0, 0);
    20
    +            }
    21
    +        </style>
    22
    +    </head>
    23
    +    <body>
    24
    +        <div class="container" >
    25
    +            <div class="weui_cells_title">机器信息</div>
    26
    +            <div class="weui_cells weui_cells_form">
    27
    +                <div class="weui_cell weui_cell_select weui_select_after">
    28
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">型号</label></div>
    29
    +                    <div class="weui_cell_bd weui_cell_primary">
    30
    +                        <select id="model" class="weui_select" name="select">
    31
    +                            {% for model in models %}
    32
    +                            <option value="{{ model.model_id }}">{{ model.model_name }}</option>
    33
    +                            {% endfor %}
    34
    +                        </select>
    35
    +                    </div>
    36
    +                </div>
    37
    +                <div class="weui_cell">
    38
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">机身码</label></div>
    39
    +                    <div class="weui_cell_bd weui_cell_primary">
    40
    +                        <input id="code" class="weui_input" type="text" value="" placeholder="请输入机身码">
    41
    +                    </div>
    42
    +                </div>
    43
    +            </div>
    44
    +
    45
    +            <div class="weui_cells_title">消费者信息</div>
    46
    +            <div class="weui_cells weui_cells_form">
    47
    +                <div class="weui_cell">
    48
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">姓名</label></div>
    49
    +                    <div class="weui_cell_bd weui_cell_primary">
    50
    +                        <input id="name" class="weui_input" type="text" value="" placeholder="请输入消费者姓名">
    51
    +                    </div>
    52
    +                </div>
    53
    +                <div class="weui_cell weui_cell_select weui_select_after">
    54
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">性别</label></div>
    55
    +                    <div class="weui_cell_bd weui_cell_primary">
    56
    +                        <select id="sex" class="weui_select" name="select">
    57
    +                            <option value="1">男</option>
    58
    +                            <option value="0">女</option>
    59
    +                        </select>
    60
    +                    </div>
    61
    +                </div>
    62
    +                <div class="weui_cell weui_cell_select weui_select_after">
    63
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">年龄</label></div>
    64
    +                    <div class="weui_cell_bd weui_cell_primary">
    65
    +                        <select id="age" class="weui_select" name="select">
    66
    +                            <option value="1">18周岁以下</option>
    67
    +                            <option value="2">60周岁以上</option>
    68
    +                        </select>
    69
    +                    </div>
    70
    +                </div>
    71
    +                <div class="weui_cell">
    72
    +                    <div class="weui_cell_hd"><label for="" class="weui_label">手机号</label></div>
    73
    +                    <div class="weui_cell_bd weui_cell_primary">
    74
    +                        <input id="phone" class="weui_input" type="text" required="required" pattern="[0-9]{11}" value="" placeholder="请输入消费者手机号">
    75
    +                    </div>
    76
    +                </div>
    77
    +            </div>
    78
    +
    79
    +            <br>
    80
    +
    81
    +            <button id="submit" class="weui_btn weui_btn_warn">确认</button>
    82
    +
    83
    +            <div class="weui_dialog_alert" id="dialog" style="display: none">
    84
    +                <div class="weui_mask"></div>
    85
    +                <div class="weui_dialog">
    86
    +                    <div class="weui_dialog_hd"><strong id="title" class="weui_dialog_title">弹窗标题</strong></div>
    87
    +                    <div id="content" class="weui_dialog_bd">弹窗内容,告知当前页面信息等</div>
    88
    +                    <div class="weui_dialog_ft">
    89
    +                        <a href="javascript:;" class="weui_btn_dialog primary">确定</a>
    90
    +                    </div>
    91
    +                </div>
    92
    +            </div>
    93
    +
    94
    +            <div id="toast" style="display: none;">
    95
    +                <div class="weui_mask_transparent"></div>
    96
    +                <div class="weui_toast">
    97
    +                    <i class="weui_icon_toast"></i>
    98
    +                    <p class="weui_toast_content">已完成</p>
    99
    +                </div>
    100
    +            </div>
    101
    +        </div>
    102
    +
    103
    +        <script src="//cdn.bootcss.com/zepto/1.1.6/zepto.min.js"></script>
    104
    +        <script>
    105
    +            $(function() {
    106
    +                function show_error_dialog(title, content) {
    107
    +                    $('#dialog #title').text(title);
    108
    +                    $('#dialog #content').text(content);
    109
    +                    $('#dialog').show();
    110
    +                }
    111
    +
    112
    +                function data_check() {
    113
    +                    var clerk_id = "{{ clerk_info.clerk_id }}";
    114
    +                    if (!clerk_id) {
    115
    +                        show_error_dialog('微信授权', '微信授权失败,请重新打开页面');
    116
    +                        return false;
    117
    +                    }
    118
    +
    119
    +                    var code = $('#code').val();
    120
    +                    if (!code) {
    121
    +                        show_error_dialog('机身码', '机身码错误,请检查重新输入');
    122
    +                        return false;
    123
    +                    }
    124
    +
    125
    +                    var name = $('#name').val();
    126
    +                    if (!name) {
    127
    +                        show_error_dialog('姓名', '姓名错误,请检查重新输入');
    128
    +                        return false;
    129
    +                    }
    130
    +
    131
    +                    var phone_valid = $('#phone').is(':valid');
    132
    +                    if (!phone_valid) {
    133
    +                        show_error_dialog('手机号', '手机号错误,请检查重新输入');
    134
    +                        return false;
    135
    +                    }
    136
    +
    137
    +                    return {
    138
    +                        clerk_id: clerk_id,
    139
    +                        model_id: $('#model option:checked').val(),
    140
    +                        code: code,
    141
    +                        name: name,
    142
    +                        sex: $('#sex option:checked').val(),
    143
    +                        age: $('#age option:checked').val(),
    144
    +                        phone: $('#phone').val(),
    145
    +                    }
    146
    +                }
    147
    +
    148
    +                $('#submit').click(function () {
    149
    +                    var check_result = data_check();
    150
    +                    if (check_result){
    151
    +                        $.ajax({
    152
    +                            type: 'POST',
    153
    +                            url: '{{ domain }}api/clerk/sale/submit',
    154
    +                            data: check_result,
    155
    +                            success: function(data) {
    156
    +                                if (data.status == 200) {
    157
    +                                    $('#toast').show();
    158
    +                                    setTimeout(function () {
    159
    +                                        $('#toast').hide();
    160
    +                                    }, 1000);
    161
    +                                } else {
    162
    +                                    show_error_dialog('错误', data.description);
    163
    +                                }
    164
    +                            }
    165
    +                        })
    166
    +                    }
    167
    +                });
    168
    +
    169
    +                $('#dialog .weui_btn_dialog').click(function () {
    170
    +                    $('#dialog').hide();
    171
    +                })
    172
    +            });
    173
    +        </script>
    174
    +        <script type="text/javascript" src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js"></script>
    175
    +        <script type="text/javascript" src="{% static 'tamron/js/jswe.js' %}?v=1"></script>
    176
    +        <script>
    177
    +            V.initWxData({
    178
    +                imgUrl: "http://pai.ai/static/pai2/img/paiai_96_96.png",
    179
    +                link: 'http://api.pai.ai/wx_oauth2?redirect_url=http://pai.ai/page/lensman&scope=snsapi_base',
    180
    +                desc: "摄影师授权",
    181
    +                title: "摄影师授权",
    182
    +                timeLine: ""
    183
    +            }, true);
    184
    +            V.hideOptionMenu();
    185
    +        </script>
    186
    +    </body>
    187
    +</html>

    + 4 - 0
    page/tests.py

    @@ -0,0 +1,4 @@
    1
    +from django.test import TestCase
    2
    +
    3
    +
    4
    +# Create your tests here.

    + 4 - 0
    page/views.py

    @@ -0,0 +1,4 @@
    1
    +from django.shortcuts import render
    2
    +
    3
    +
    4
    +# Create your views here.

    BIN
    page/views.pyc


    + 9 - 0
    pep8.sh

    @@ -0,0 +1,9 @@
    1
    +#!/bin/bash
    2
    +
    3
    +# Ignoring autogenerated files
    4
    +#  -- Migration directories
    5
    +# Ignoring error codes
    6
    +#  -- E128 continuation line under-indented for visual indent
    7
    +#  -- E501 line too long
    8
    +
    9
    +pep8 --exclude=migrations --ignore=E128,E501 .

    + 0 - 0
    product/__init__.py


    BIN
    product/__init__.pyc


    + 29 - 0
    product/admin.py

    @@ -0,0 +1,29 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from django.contrib import admin
    4
    +
    5
    +from product.models import ProductCodeSubmitLogInfo, ProductInfo, ProductModelInfo
    6
    +
    7
    +
    8
    +class ProductModelInfoAdmin(admin.ModelAdmin):
    9
    +    readonly_fields = ('model_id', )
    10
    +    list_display = ('model_id', 'model_name', 'integral', 'status', 'created_at', 'updated_at')
    11
    +    search_fields = ('model_id', 'model_name')
    12
    +    list_filter = ('status', )
    13
    +
    14
    +
    15
    +class ProductInfoAdmin(admin.ModelAdmin):
    16
    +    list_display = ('model_id', 'model_name', 'code', 'code_status', 'integral', 'integral_status', 'franchiser_id', 'clerk_id', 'consumer_name', 'consumer_sex', 'consumer_age', 'consumer_phone', 'status', 'created_at', 'updated_at')
    17
    +    search_fields = ('model_id', 'model_name', 'code', 'consumer_name', 'consumer_phone')
    18
    +    list_filter = ('code_status', 'integral_status', 'franchiser_id', 'consumer_sex', 'status')
    19
    +
    20
    +
    21
    +class ProductCodeSubmitLogInfoAdmin(admin.ModelAdmin):
    22
    +    list_display = ('model_id', 'model_name', 'code', 'franchiser_id', 'clerk_id', 'consumer_name', 'consumer_sex', 'consumer_age', 'consumer_phone', 'status', 'created_at', 'updated_at')
    23
    +    search_fields = ('model_id', 'model_name', 'code', 'consumer_name', 'consumer_phone')
    24
    +    list_filter = ('franchiser_id', 'consumer_sex', 'status')
    25
    +
    26
    +
    27
    +admin.site.register(ProductModelInfo, ProductModelInfoAdmin)
    28
    +admin.site.register(ProductInfo, ProductInfoAdmin)
    29
    +admin.site.register(ProductCodeSubmitLogInfo, ProductCodeSubmitLogInfoAdmin)

    BIN
    product/admin.pyc


    + 77 - 0
    product/migrations/0001_initial.py

    @@ -0,0 +1,77 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +from __future__ import unicode_literals
    3
    +
    4
    +from django.db import models, migrations
    5
    +import shortuuidfield.fields
    6
    +
    7
    +
    8
    +class Migration(migrations.Migration):
    9
    +
    10
    +    dependencies = [
    11
    +    ]
    12
    +
    13
    +    operations = [
    14
    +        migrations.CreateModel(
    15
    +            name='ProductCodeSubmitLogInfo',
    16
    +            fields=[
    17
    +                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
    18
    +                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
    19
    +                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
    20
    +                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
    21
    +                ('model_id', models.CharField(max_length=255, blank=True, help_text='\u578b\u53f7\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='model_id', db_index=True)),
    22
    +                ('model_name', models.CharField(max_length=255, blank=True, help_text='\u578b\u53f7\u540d\u79f0', null=True, verbose_name='model_name', db_index=True)),
    23
    +                ('code', models.CharField(help_text='\u673a\u8eab\u7801', max_length=255, null=True, verbose_name='code', blank=True)),
    24
    +                ('franchiser_id', models.CharField(max_length=255, blank=True, help_text='\u7ecf\u9500\u5546\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='franchiser_id', db_index=True)),
    25
    +                ('clerk_id', models.CharField(max_length=255, blank=True, help_text='\u5e97\u5458\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='clerk_id', db_index=True)),
    26
    +                ('consumer_name', models.CharField(help_text='\u6d88\u8d39\u8005\u540d\u79f0', max_length=255, null=True, verbose_name='consumer_name', blank=True)),
    27
    +                ('consumer_sex', models.IntegerField(default=1, help_text='\u6d88\u8d39\u8005\u6027\u522b', db_index=True, verbose_name='consumer_sex', choices=[(1, '\u7537'), (0, '\u5973')])),
    28
    +                ('consumer_age', models.IntegerField(default=0, help_text='\u6d88\u8d39\u8005\u5e74\u9f84', verbose_name='consumer_age')),
    29
    +                ('consumer_phone', models.CharField(help_text='\u6d88\u8d39\u8005\u8054\u7cfb\u7535\u8bdd', max_length=255, null=True, verbose_name='consumer_phone', blank=True)),
    30
    +            ],
    31
    +            options={
    32
    +                'verbose_name': 'productcodesubmitloginfo',
    33
    +                'verbose_name_plural': 'productcodesubmitloginfo',
    34
    +            },
    35
    +        ),
    36
    +        migrations.CreateModel(
    37
    +            name='ProductInfo',
    38
    +            fields=[
    39
    +                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
    40
    +                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
    41
    +                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
    42
    +                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
    43
    +                ('model_id', models.CharField(max_length=255, blank=True, help_text='\u578b\u53f7\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='model_id', db_index=True)),
    44
    +                ('model_name', models.CharField(max_length=255, blank=True, help_text='\u578b\u53f7\u540d\u79f0', null=True, verbose_name='model_name', db_index=True)),
    45
    +                ('code', models.CharField(help_text='\u673a\u8eab\u7801', max_length=255, null=True, verbose_name='code', blank=True)),
    46
    +                ('code_status', models.BooleanField(default=False, help_text='\u673a\u8eab\u7801\u72b6\u6001', db_index=True, verbose_name='code_status')),
    47
    +                ('integral', models.IntegerField(default=0, help_text='\u79ef\u5206', verbose_name='integral')),
    48
    +                ('integral_status', models.BooleanField(default=False, help_text='\u79ef\u5206\u72b6\u6001', db_index=True, verbose_name='integral_status')),
    49
    +                ('franchiser_id', models.CharField(max_length=255, blank=True, help_text='\u7ecf\u9500\u5546\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='franchiser_id', db_index=True)),
    50
    +                ('clerk_id', models.CharField(max_length=255, blank=True, help_text='\u5e97\u5458\u552f\u4e00\u6807\u8bc6', null=True, verbose_name='clerk_id', db_index=True)),
    51
    +                ('consumer_name', models.CharField(help_text='\u6d88\u8d39\u8005\u540d\u79f0', max_length=255, null=True, verbose_name='consumer_name', blank=True)),
    52
    +                ('consumer_sex', models.IntegerField(default=1, help_text='\u6d88\u8d39\u8005\u6027\u522b', db_index=True, verbose_name='consumer_sex', choices=[(1, '\u7537'), (0, '\u5973')])),
    53
    +                ('consumer_age', models.IntegerField(default=0, help_text='\u6d88\u8d39\u8005\u5e74\u9f84', verbose_name='consumer_age')),
    54
    +                ('consumer_phone', models.CharField(help_text='\u6d88\u8d39\u8005\u8054\u7cfb\u7535\u8bdd', max_length=255, null=True, verbose_name='consumer_phone', blank=True)),
    55
    +            ],
    56
    +            options={
    57
    +                'verbose_name': 'productinfo',
    58
    +                'verbose_name_plural': 'productinfo',
    59
    +            },
    60
    +        ),
    61
    +        migrations.CreateModel(
    62
    +            name='ProductModelInfo',
    63
    +            fields=[
    64
    +                ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
    65
    +                ('status', models.BooleanField(default=True, help_text='\u72b6\u6001', db_index=True, verbose_name='status')),
    66
    +                ('created_at', models.DateTimeField(help_text='\u521b\u5efa\u65f6\u95f4', verbose_name='created_at', auto_now_add=True)),
    67
    +                ('updated_at', models.DateTimeField(help_text='\u66f4\u65b0\u65f6\u95f4', verbose_name='updated_at', auto_now=True)),
    68
    +                ('model_id', shortuuidfield.fields.ShortUUIDField(editable=False, max_length=22, blank=True, help_text='\u578b\u53f7\u552f\u4e00\u6807\u8bc6', unique=True, db_index=True)),
    69
    +                ('model_name', models.CharField(help_text='\u578b\u53f7\u540d\u79f0', max_length=255, null=True, verbose_name='model_name', blank=True)),
    70
    +                ('integral', models.IntegerField(default=0, help_text='\u578b\u53f7\u79ef\u5206', verbose_name='integral')),
    71
    +            ],
    72
    +            options={
    73
    +                'verbose_name': '\u4ea7\u54c1\u578b\u53f7\u4fe1\u606f',
    74
    +                'verbose_name_plural': '\u4ea7\u54c1\u578b\u53f7\u4fe1\u606f',
    75
    +            },
    76
    +        ),
    77
    +    ]

    BIN
    product/migrations/0001_initial.pyc


    + 24 - 0
    product/migrations/0002_auto_20170619_1734.py

    @@ -0,0 +1,24 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +from __future__ import unicode_literals
    3
    +
    4
    +from django.db import models, migrations
    5
    +
    6
    +
    7
    +class Migration(migrations.Migration):
    8
    +
    9
    +    dependencies = [
    10
    +        ('product', '0001_initial'),
    11
    +    ]
    12
    +
    13
    +    operations = [
    14
    +        migrations.AlterField(
    15
    +            model_name='productinfo',
    16
    +            name='code_status',
    17
    +            field=models.BooleanField(default=False, help_text='\u673a\u8eab\u7801\u72b6\u6001, True\u5df2\u4f7f\u7528\uff0cFalse\u672a\u4f7f\u7528', db_index=True, verbose_name='code_status'),
    18
    +        ),
    19
    +        migrations.AlterField(
    20
    +            model_name='productinfo',
    21
    +            name='integral_status',
    22
    +            field=models.BooleanField(default=False, help_text='\u79ef\u5206\u72b6\u6001, True\u5df2\u79ef\u5206\uff0cFalse\u672a\u79ef\u5206', db_index=True, verbose_name='integral_status'),
    23
    +        ),
    24
    +    ]

    BIN
    product/migrations/0002_auto_20170619_1734.pyc


    + 0 - 0
    product/migrations/__init__.py


    BIN
    product/migrations/__init__.pyc


    + 99 - 0
    product/models.py

    @@ -0,0 +1,99 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from django.db import models
    4
    +from django.utils.translation import ugettext_lazy as _
    5
    +from shortuuidfield import ShortUUIDField
    6
    +
    7
    +from tamron.basemodels import CreateUpdateMixin
    8
    +
    9
    +
    10
    +class ProductModelInfo(CreateUpdateMixin):
    11
    +    model_id = ShortUUIDField(_(u'model_id'), max_length=255, help_text=u'型号唯一标识', db_index=True, unique=True)
    12
    +    model_name = models.CharField(_(u'model_name'), max_length=255, blank=True, null=True, help_text=u'型号名称')
    13
    +    integral = models.IntegerField(_(u'integral'), default=0, help_text=u'型号积分')
    14
    +
    15
    +    class Meta:
    16
    +        verbose_name = _(u'产品型号信息')
    17
    +        verbose_name_plural = _(u'产品型号信息')
    18
    +
    19
    +    def __unicode__(self):
    20
    +        return unicode(self.pk)
    21
    +
    22
    +    @property
    23
    +    def data(self):
    24
    +        return {
    25
    +            'model_id': self.model_id,
    26
    +            'model_name': self.model_name,
    27
    +            'integral': self.integral,
    28
    +        }
    29
    +
    30
    +
    31
    +class ProductInfo(CreateUpdateMixin):
    32
    +    MALE = 1
    33
    +    FEMALE = 0
    34
    +
    35
    +    SEX_TYPE = (
    36
    +        (MALE, u'男'),
    37
    +        (FEMALE, u'女'),
    38
    +    )
    39
    +
    40
    +    model_id = models.CharField(_(u'model_id'), max_length=255, blank=True, null=True, help_text=u'型号唯一标识', db_index=True)
    41
    +    model_name = models.CharField(_(u'model_name'), max_length=255, blank=True, null=True, help_text=u'型号名称', db_index=True)
    42
    +
    43
    +    code = models.CharField(_(u'code'), max_length=255, blank=True, null=True, help_text=u'机身码')
    44
    +    code_status = models.BooleanField(_(u'code_status'), default=False, help_text=u'机身码状态, True已使用,False未使用', db_index=True)
    45
    +
    46
    +    integral = models.IntegerField(_(u'integral'), default=0, help_text=u'积分')
    47
    +    integral_status = models.BooleanField(_(u'integral_status'), default=False, help_text=u'积分状态, True已积分,False未积分', db_index=True)
    48
    +
    49
    +    franchiser_id = models.CharField(_(u'franchiser_id'), max_length=255, blank=True, null=True, help_text=u'经销商唯一标识', db_index=True)
    50
    +    clerk_id = models.CharField(_(u'clerk_id'), max_length=255, blank=True, null=True, help_text=u'店员唯一标识', db_index=True)
    51
    +
    52
    +    consumer_name = models.CharField(_(u'consumer_name'), max_length=255, blank=True, null=True, help_text=u'消费者名称')
    53
    +    consumer_sex = models.IntegerField(_(u'consumer_sex'), choices=SEX_TYPE, default=MALE, help_text=u'消费者性别', db_index=True)
    54
    +    consumer_age = models.IntegerField(_(u'consumer_age'), default=0, help_text=u'消费者年龄')
    55
    +    consumer_phone = models.CharField(_(u'consumer_phone'), max_length=255, blank=True, null=True, help_text=u'消费者联系电话')
    56
    +
    57
    +    class Meta:
    58
    +        verbose_name = _(u'productinfo')
    59
    +        verbose_name_plural = _(u'productinfo')
    60
    +
    61
    +    def __unicode__(self):
    62
    +        return unicode(self.pk)
    63
    +
    64
    +    @property
    65
    +    def data(self):
    66
    +        return {
    67
    +            'model_id': self.model_id,
    68
    +            'model_name': self.model_name,
    69
    +            'code': self.code,
    70
    +        }
    71
    +
    72
    +
    73
    +class ProductCodeSubmitLogInfo(CreateUpdateMixin):
    74
    +    MALE = 1
    75
    +    FEMALE = 0
    76
    +
    77
    +    SEX_TYPE = (
    78
    +        (MALE, u'男'),
    79
    +        (FEMALE, u'女'),
    80
    +    )
    81
    +
    82
    +    model_id = models.CharField(_(u'model_id'), max_length=255, blank=True, null=True, help_text=u'型号唯一标识', db_index=True)
    83
    +    model_name = models.CharField(_(u'model_name'), max_length=255, blank=True, null=True, help_text=u'型号名称', db_index=True)
    84
    +    code = models.CharField(_(u'code'), max_length=255, blank=True, null=True, help_text=u'机身码')
    85
    +
    86
    +    franchiser_id = models.CharField(_(u'franchiser_id'), max_length=255, blank=True, null=True, help_text=u'经销商唯一标识', db_index=True)
    87
    +    clerk_id = models.CharField(_(u'clerk_id'), max_length=255, blank=True, null=True, help_text=u'店员唯一标识', db_index=True)
    88
    +
    89
    +    consumer_name = models.CharField(_(u'consumer_name'), max_length=255, blank=True, null=True, help_text=u'消费者名称')
    90
    +    consumer_sex = models.IntegerField(_(u'consumer_sex'), choices=SEX_TYPE, default=MALE, help_text=u'消费者性别', db_index=True)
    91
    +    consumer_age = models.IntegerField(_(u'consumer_age'), default=0, help_text=u'消费者年龄')
    92
    +    consumer_phone = models.CharField(_(u'consumer_phone'), max_length=255, blank=True, null=True, help_text=u'消费者联系电话')
    93
    +
    94
    +    class Meta:
    95
    +        verbose_name = _(u'productcodesubmitloginfo')
    96
    +        verbose_name_plural = _(u'productcodesubmitloginfo')
    97
    +
    98
    +    def __unicode__(self):
    99
    +        return unicode(self.pk)

    BIN
    product/models.pyc


    + 4 - 0
    product/tests.py

    @@ -0,0 +1,4 @@
    1
    +from django.test import TestCase
    2
    +
    3
    +
    4
    +# Create your tests here.

    + 4 - 0
    product/views.py

    @@ -0,0 +1,4 @@
    1
    +from django.shortcuts import render
    2
    +
    3
    +
    4
    +# Create your views here.

    + 39 - 0
    requirements.txt

    @@ -0,0 +1,39 @@
    1
    +-e git+https://github.com/Brightcells/django-q.git#egg=django-q
    2
    +-e git+https://github.com/andymccurdy/redis-py.git#egg=redis-py
    3
    +CodeConvert==2.0.4
    4
    +Django==1.8.4
    5
    +MySQL-python==1.2.5
    6
    +Pillow==3.4.2
    7
    +StatusCode==1.0.0
    8
    +TimeConvert==1.4.1
    9
    +cryptography==1.5.2
    10
    +django-curtail-uuid==1.0.0
    11
    +django-detect==1.0.5
    12
    +django-file-md5==1.0.1
    13
    +django-ip==1.0.0
    14
    +django-json-response==1.1.4
    15
    +django-logit==1.0.6
    16
    +django-multidomain==1.1.4
    17
    +django-paginator2==1.0.3
    18
    +django-rlog==1.0.7
    19
    +django-shortuuidfield==0.1.3
    20
    +django-six==1.0.2
    21
    +djangorestframework==3.6.3
    22
    +furl==1.0.0
    23
    +hiredis==0.2.0
    24
    +isoweek==1.3.3
    25
    +jsonfield==2.0.2
    26
    +mock==2.0.0
    27
    +pep8==1.7.0
    28
    +pysnippets==1.0.4
    29
    +pywe-miniapp==1.0.0
    30
    +pywe-oauth==1.0.3
    31
    +pywe-response==1.0.1
    32
    +qiniu==7.1.4
    33
    +redis-extensions==1.0.50
    34
    +requests==2.12.4
    35
    +rlog==0.2
    36
    +shortuuid==0.5.0
    37
    +uWSGI==2.0.15
    38
    +versions==0.10.0
    39
    +wechatpy==1.2.8

    + 0 - 0
    tamron/__init__.py


    BIN
    tamron/__init__.pyc


    + 13 - 0
    tamron/basemodels.py

    @@ -0,0 +1,13 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from django.db import models
    4
    +from django.utils.translation import ugettext_lazy as _
    5
    +
    6
    +
    7
    +class CreateUpdateMixin(models.Model):
    8
    +    status = models.BooleanField(_(u'status'), default=True, help_text=_(u'状态'), db_index=True)
    9
    +    created_at = models.DateTimeField(_(u'created_at'), auto_now_add=True, editable=True, help_text=_(u'创建时间'))
    10
    +    updated_at = models.DateTimeField(_(u'updated_at'), auto_now=True, editable=True, help_text=_(u'更新时间'))
    11
    +
    12
    +    class Meta:
    13
    +        abstract = True

    BIN
    tamron/basemodels.pyc


    + 16 - 0
    tamron/func_settings.py

    @@ -0,0 +1,16 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +import redis_extensions as redis
    4
    +
    5
    +
    6
    +def redis_conf(conf):
    7
    +    return {
    8
    +        'host': conf.get('HOST', 'localhost'),
    9
    +        'port': conf.get('PORT', 6379),
    10
    +        'password': '{}:{}'.format(conf.get('USER', ''), conf.get('PASSWORD', '')) if conf.get('USER') else '',
    11
    +        'db': conf.get('db', 0),
    12
    +    }
    13
    +
    14
    +
    15
    +def redis_connect(conf):
    16
    +    return redis.StrictRedisExtensions(connection_pool=redis.ConnectionPool(**redis_conf(conf)))

    BIN
    tamron/func_settings.pyc


    + 29 - 0
    tamron/local_settings.py

    @@ -0,0 +1,29 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +import os
    4
    +
    5
    +
    6
    +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    7
    +PROJ_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))
    8
    +
    9
    +TEMPLATES = [
    10
    +    {
    11
    +        'BACKEND': 'django.template.backends.django.DjangoTemplates',
    12
    +        'DIRS': [os.path.join(BASE_DIR, 'templates')],
    13
    +        # 'APP_DIRS': True,
    14
    +        'OPTIONS': {
    15
    +            'context_processors': [
    16
    +                'django.template.context_processors.debug',
    17
    +                'django.template.context_processors.request',
    18
    +                'django.contrib.auth.context_processors.auth',
    19
    +                'django.contrib.messages.context_processors.messages',
    20
    +            ],
    21
    +            'loaders': [
    22
    +                'django.template.loaders.filesystem.Loader',
    23
    +                'django.template.loaders.app_directories.Loader',
    24
    +            ],
    25
    +        },
    26
    +    },
    27
    +]
    28
    +
    29
    +DOMAIN = 'http://127.0.0.1:9997/'

    BIN
    tamron/local_settings.pyc


    + 254 - 0
    tamron/settings.py

    @@ -0,0 +1,254 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +"""
    4
    +Django settings for tamron project.
    5
    +
    6
    +Generated by 'django-admin startproject' using Django 1.8.4.
    7
    +
    8
    +For more information on this file, see
    9
    +https://docs.djangoproject.com/en/1.8/topics/settings/
    10
    +
    11
    +For the full list of settings and their values, see
    12
    +https://docs.djangoproject.com/en/1.8/ref/settings/
    13
    +"""
    14
    +
    15
    +# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
    16
    +import os
    17
    +
    18
    +
    19
    +BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    20
    +PROJ_DIR = os.path.abspath(os.path.dirname(os.path.abspath(__file__)))
    21
    +
    22
    +
    23
    +# Quick-start development settings - unsuitable for production
    24
    +# See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
    25
    +
    26
    +# SECURITY WARNING: keep the secret key used in production secret!
    27
    +SECRET_KEY = '@!_8xi9(8)gj8zvni#)2-arn)4gn^u&coy-0yld0=1r5*ao@4i'
    28
    +
    29
    +# SECURITY WARNING: don't run with debug turned on in production!
    30
    +DEBUG = True
    31
    +
    32
    +ALLOWED_HOSTS = []
    33
    +
    34
    +
    35
    +# Application definition
    36
    +
    37
    +INSTALLED_APPS = (
    38
    +    'django.contrib.admin',
    39
    +    'django.contrib.auth',
    40
    +    'django.contrib.contenttypes',
    41
    +    'django.contrib.sessions',
    42
    +    'django.contrib.messages',
    43
    +    'django.contrib.staticfiles',
    44
    +    'api',
    45
    +    'account',
    46
    +    'integral',
    47
    +    'page',
    48
    +    'product',
    49
    +)
    50
    +
    51
    +MIDDLEWARE_CLASSES = (
    52
    +    'django.contrib.sessions.middleware.SessionMiddleware',
    53
    +    'django.middleware.common.CommonMiddleware',
    54
    +    # 'django.middleware.csrf.CsrfViewMiddleware',
    55
    +    'django.contrib.auth.middleware.AuthenticationMiddleware',
    56
    +    'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
    57
    +    'django.contrib.messages.middleware.MessageMiddleware',
    58
    +    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    59
    +    'django.middleware.security.SecurityMiddleware',
    60
    +)
    61
    +
    62
    +ROOT_URLCONF = 'tamron.urls'
    63
    +
    64
    +TEMPLATES = [
    65
    +    {
    66
    +        'BACKEND': 'django.template.backends.django.DjangoTemplates',
    67
    +        'DIRS': [os.path.join(BASE_DIR, 'templates')],
    68
    +        # 'APP_DIRS': True,
    69
    +        'OPTIONS': {
    70
    +            'context_processors': [
    71
    +                'django.template.context_processors.debug',
    72
    +                'django.template.context_processors.request',
    73
    +                'django.contrib.auth.context_processors.auth',
    74
    +                'django.contrib.messages.context_processors.messages',
    75
    +            ],
    76
    +            'loaders': [
    77
    +                ('django.template.loaders.cached.Loader', [
    78
    +                    'django.template.loaders.filesystem.Loader',
    79
    +                    'django.template.loaders.app_directories.Loader',
    80
    +                ]),
    81
    +            ],
    82
    +        },
    83
    +    },
    84
    +]
    85
    +
    86
    +WSGI_APPLICATION = 'tamron.wsgi.application'
    87
    +
    88
    +
    89
    +# Database
    90
    +# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
    91
    +
    92
    +DATABASES = {
    93
    +    'default': {
    94
    +        'ENGINE': 'django.db.backends.mysql',
    95
    +        'NAME': 'tamron',
    96
    +        'USER': 'root',
    97
    +        'PASSWORD': '',
    98
    +        'CONN_MAX_AGE': 600,
    99
    +        'OPTIONS': {
    100
    +            # Utf8mb4 for Emoji
    101
    +            #
    102
    +            # Nickname
    103
    +            #
    104
    +            # account.WechatInfo ==> nickname
    105
    +            #   ALTER TABLE account_wechatinfo MODIFY COLUMN nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
    106
    +            # account.UserInfo ==> nickname
    107
    +            #   ALTER TABLE account_userinfo MODIFY COLUMN nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
    108
    +            # group.GroupUserInfo ==> nickname
    109
    +            #   ALTER TABLE group_groupuserinfo MODIFY COLUMN nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL;
    110
    +            # group.GroupPhotoInfo ==> nickname
    111
    +            #   ALTER TABLE group_groupphotoinfo MODIFY COLUMN nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL;
    112
    +            # group.PhotoCommentInfo ==> nickname
    113
    +            #   ALTER TABLE group_photocommentinfo MODIFY COLUMN nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL;
    114
    +            # group.PhotoThumbUpInfo ==> nickname
    115
    +            #   ALTER TABLE group_photothumbupinfo MODIFY COLUMN nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL;
    116
    +            # group.UserMessageInfo ==> nickname
    117
    +            #   ALTER TABLE message_usermessageinfo MODIFY COLUMN from_nickname VARCHAR(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL;
    118
    +            #
    119
    +            # Comment
    120
    +            # group.PhotoCommentInfo ==> comment
    121
    +            #   ALTER TABLE group_photocommentinfo MODIFY COLUMN comment LONGTEXT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
    122
    +            'charset': 'utf8mb4',
    123
    +        },
    124
    +    }
    125
    +}
    126
    +
    127
    +
    128
    +# Internationalization
    129
    +# https://docs.djangoproject.com/en/1.8/topics/i18n/
    130
    +
    131
    +LANGUAGE_CODE = 'zh-Hans'
    132
    +
    133
    +TIME_ZONE = 'Asia/Shanghai'
    134
    +
    135
    +USE_I18N = True
    136
    +
    137
    +USE_L10N = True
    138
    +
    139
    +USE_TZ = True
    140
    +
    141
    +
    142
    +# Static files (CSS, JavaScript, Images)
    143
    +# https://docs.djangoproject.com/en/1.8/howto/static-files/
    144
    +
    145
    +STATICFILES_DIRS = (
    146
    +    os.path.join(PROJ_DIR, 'static').replace('\\', '/'),
    147
    +)
    148
    +
    149
    +STATIC_ROOT = os.path.join(BASE_DIR, 'collect_static').replace('\\', '/')
    150
    +
    151
    +STATIC_URL = '/static/'
    152
    +
    153
    +STATICFILES_FINDERS = (
    154
    +    'django.contrib.staticfiles.finders.FileSystemFinder',
    155
    +    'django.contrib.staticfiles.finders.AppDirectoriesFinder',
    156
    +    # 'django.contrib.staticfiles.finders.DefaultStorageFinder',
    157
    +)
    158
    +
    159
    +MEDIA_ROOT = os.path.join(BASE_DIR, 'media').replace('\\', '/')
    160
    +
    161
    +MEDIA_URL = '/media/'
    162
    +
    163
    +# Redis 设置
    164
    +REDIS = {
    165
    +    'default': {
    166
    +        'HOST': '127.0.0.1',
    167
    +        'PORT': 6379,
    168
    +        'USER': '',
    169
    +        'PASSWORD': '',
    170
    +        'db': 0,
    171
    +    }
    172
    +}
    173
    +
    174
    +# 微信设置
    175
    +WECHAT = {
    176
    +    'JSAPI': {
    177
    +        'token': '5201314',
    178
    +        'appID': '',
    179
    +        'appsecret': '',
    180
    +        'mchID': '',
    181
    +        'apiKey': '',
    182
    +        'mch_cert': '',
    183
    +        'mch_key': '',
    184
    +        'redpacket': {
    185
    +
    186
    +        }
    187
    +    },
    188
    +}
    189
    +
    190
    +# 微信授权设置
    191
    +WECHAT_BASE_REDIRECT_URI = 'https://api.pai.ai/base_redirect'
    192
    +WECHAT_USERINFO_REDIRECT_URI = 'https://api.pai.ai/userinfo_redirect'
    193
    +WECHAT_OAUTH2_RETRY_REDIRECT_URI = 'https://api.pai.ai/wx_oauth2?redirect_url={}'
    194
    +
    195
    +WECHAT_OAUTH2_REDIRECT_URL = 'https://api.pai.ai/wx_oauth2?redirect_url={}'
    196
    +
    197
    +# LOGIT 设置
    198
    +LOGIT_BODY_FLAG = True
    199
    +LOGIT_RES_FLAG = True
    200
    +
    201
    +DOMAIN = ''
    202
    +
    203
    +try:
    204
    +    from local_settings import *
    205
    +except ImportError:
    206
    +    pass
    207
    +
    208
    +try:
    209
    +    from func_settings import redis_connect
    210
    +    REDIS_CACHE = redis_connect(REDIS.get('default', {}))
    211
    +
    212
    +    DJLOGIT = {
    213
    +        'level': 'DEBUG',
    214
    +        'class': 'rlog.RedisListHandler',
    215
    +        'redis_client': REDIS_CACHE,
    216
    +        'key': 'django:logit:tamron',
    217
    +        'formatter': 'verbose',
    218
    +    }
    219
    +except ImportError:
    220
    +    REDIS_CACHE = None
    221
    +
    222
    +# 日志设置
    223
    +LOGGING = {
    224
    +    'version': 1,
    225
    +    'disable_existing_loggers': False,
    226
    +    'formatters': {
    227
    +        'verbose': {
    228
    +            'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
    229
    +        },
    230
    +        'simple': {
    231
    +            'format': '%(levelname)s %(message)s'
    232
    +        },
    233
    +    },
    234
    +    'handlers': {
    235
    +        'logit': DJLOGIT,
    236
    +        'console': {
    237
    +            'level': 'DEBUG',
    238
    +            'class': 'logging.StreamHandler',
    239
    +            'formatter': 'verbose'
    240
    +        },
    241
    +    },
    242
    +    'loggers': {
    243
    +        'logit': {
    244
    +            'handlers': ['logit'],
    245
    +            'level': 'DEBUG',
    246
    +            'propagate': True,
    247
    +        },
    248
    +        'console': {
    249
    +            'handlers': ['console'],
    250
    +            'level': 'DEBUG',
    251
    +            'propagate': True,
    252
    +        },
    253
    +    },
    254
    +}

    BIN
    tamron/settings.pyc


    + 300 - 0
    tamron/static/tamron/js/jswe.js

    @@ -0,0 +1,300 @@
    1
    +!(function(e, t) {
    2
    +    var config = {
    3
    +        wxconfig: 'http://api.pai.ai/wx/jsapi_signature',
    4
    +        callback: 'callback'
    5
    +    }, wxData = {
    6
    +        debug: false,
    7
    +        imgUrl: '',
    8
    +        link: '',
    9
    +        desc: '',
    10
    +        title: '',
    11
    +        timeLine: ''
    12
    +    }, wxConfig = {
    13
    +        hide: false,
    14
    +        close: false
    15
    +    }, jsApiList = [
    16
    +        'checkJsApi',
    17
    +        'onMenuShareTimeline',
    18
    +        'onMenuShareAppMessage',
    19
    +        'onMenuShareQQ',
    20
    +        'onMenuShareWeibo',
    21
    +        'hideMenuItems',
    22
    +        'showMenuItems',
    23
    +        'hideAllNonBaseMenuItem',
    24
    +        'showAllNonBaseMenuItem',
    25
    +        'translateVoice',
    26
    +        'startRecord',
    27
    +        'stopRecord',
    28
    +        'onRecordEnd',
    29
    +        'playVoice',
    30
    +        'pauseVoice',
    31
    +        'stopVoice',
    32
    +        'uploadVoice',
    33
    +        'downloadVoice',
    34
    +        'chooseImage',
    35
    +        'previewImage',
    36
    +        'uploadImage',
    37
    +        'downloadImage',
    38
    +        'getNetworkType',
    39
    +        'openLocation',
    40
    +        'getLocation',
    41
    +        'hideOptionMenu',
    42
    +        'showOptionMenu',
    43
    +        'closeWindow',
    44
    +        'scanQRCode',
    45
    +        'chooseWXPay',
    46
    +        'openEnterpriseRedPacket',
    47
    +        'openProductSpecificView',
    48
    +        'addCard',
    49
    +        'chooseCard',
    50
    +        'openCard'
    51
    +    ], wxApiFun
    52
    +
    53
    +    function isOpenOnPC() {  // 判断当前网页是否在 PC 浏览器中打开
    54
    +        var ua = navigator.userAgent
    55
    +        return /windows nt/i.test(ua) || /macintosh/i.test(ua) || /linux x86_64/i.test(ua)
    56
    +    }
    57
    +
    58
    +    function isOpenInWeixin() {  // 判断当前网页是否在微信内置浏览器中打开
    59
    +        return /micromessenger/i.test(navigator.userAgent)
    60
    +    }
    61
    +
    62
    +    function getWeixinVersion() {
    63
    +        var ua = navigator.userAgent,
    64
    +            mt = ua.match(/micromessenger\/([\d.]+)/i)
    65
    +        return (mt ? mt[1] : '')
    66
    +    }
    67
    +
    68
    +    // This function checks whether Wechat is the appointed version or not
    69
    +    // Cmp: http://jsperf.com/regexp-test-vs-indexof-ignore-upper-and-lower
    70
    +    function isWeixinVersion(version) {
    71
    +        // return new RegExp('micromessenger/' + version , 'i').test(navigator.userAgent)
    72
    +        return navigator.userAgent.toLowerCase().indexOf('micromessenger/' + version) != -1
    73
    +    }
    74
    +
    75
    +    function hideOptionMenu() {
    76
    +        wxConfig.hide = true
    77
    +        fixedWxData()
    78
    +    }
    79
    +
    80
    +    function showOptionMenu() {
    81
    +        wxConfig.hide = false
    82
    +        fixedWxData()
    83
    +    }
    84
    +
    85
    +    function closeWindow() {
    86
    +        wxConfig.close = true
    87
    +        fixedWxData()
    88
    +    }
    89
    +
    90
    +    function wxReady(data) {
    91
    +        data = typeof data === 'object' ? data : JSON.parse(data)
    92
    +        wx.config({
    93
    +            debug: wxData.debug,
    94
    +            appId: data.appId,
    95
    +            timestamp: data.timestamp,
    96
    +            nonceStr: data.nonceStr,
    97
    +            signature: data.signature,
    98
    +            jsApiList: jsApiList
    99
    +        })
    100
    +
    101
    +        var callbacks = {
    102
    +            trigger: function (res) {
    103
    +                // alert('用户点击发送给朋友')
    104
    +                if (JSWE.wxTrigger) {JSWE.wxTrigger(res)}
    105
    +            },
    106
    +            success: function (res) {
    107
    +                // alert('已分享')
    108
    +                if (JSWE.wxSuccess) {JSWE.wxSuccess(res)}
    109
    +            },
    110
    +            cancel: function (res) {
    111
    +                // alert('已取消')
    112
    +                if (JSWE.wxCancel) {JSWE.wxCancel(res)}
    113
    +            },
    114
    +            fail: function (res) {
    115
    +                // alert(JSON.stringify(res))
    116
    +                if (JSWE.wxFail) {JSWE.wxFail(res)}
    117
    +            }
    118
    +        }, shareInfo = function(flag) {
    119
    +            var _share = {
    120
    +                title: flag ? wxData.title : (wxData.timeLine || wxData.desc),
    121
    +                link: wxData.link,
    122
    +                imgUrl: wxData.imgUrl,
    123
    +                trigger: callbacks.trigger,
    124
    +                success: callbacks.success,
    125
    +                cancel: callbacks.cancel,
    126
    +                fail: callbacks.fail
    127
    +            }
    128
    +            if (flag) _share.desc = wxData.desc
    129
    +            return _share
    130
    +        }, wxShareApi = function() {
    131
    +            // 2. 分享接口
    132
    +            // 2.1 监听“分享给朋友”,按钮点击、自定义分享内容及分享结果接口
    133
    +            wx.onMenuShareAppMessage(shareInfo(1))
    134
    +            // 2.2 监听“分享到朋友圈”按钮点击、自定义分享内容及分享结果接口
    135
    +            wx.onMenuShareTimeline(shareInfo(0))
    136
    +            // 2.3 监听“分享到QQ”按钮点击、自定义分享内容及分享结果接口
    137
    +            wx.onMenuShareQQ(shareInfo(1))
    138
    +            // 2.4 监听“分享到微博”按钮点击、自定义分享内容及分享结果接口
    139
    +            wx.onMenuShareWeibo(shareInfo(1))
    140
    +        }, wxMenuApi = function () {
    141
    +            // 8. 界面操作接口
    142
    +            // 8.1 隐藏右上角菜单
    143
    +            // 8.2 显示右上角菜单
    144
    +            if (wxConfig.hide) {wx.hideOptionMenu()} else {wx.showOptionMenu()}
    145
    +            // 8.7 关闭当前窗口
    146
    +            if (wxConfig.close) {wx.closeWindow()}
    147
    +        }, wxApi = function () {
    148
    +            wxShareApi()
    149
    +            wxMenuApi()
    150
    +        }
    151
    +
    152
    +        wx.ready(wxApi)
    153
    +
    154
    +        return wxApiFun = wxApi
    155
    +    }
    156
    +
    157
    +    if (isOpenInWeixin() || isOpenOnPC()) {
    158
    +        if ('undefined' !== typeof JSWE_CONF_UPDATE) JSWE_CONF_UPDATE(config)
    159
    +        $.ajax({
    160
    +            url: config.wxconfig,
    161
    +            type: 'get',
    162
    +            dataType: 'jsonp',
    163
    +            jsonpCallback: config.callback,
    164
    +            data: {
    165
    +                url: window.location.href.split('#')[0]
    166
    +            },
    167
    +            success: wxReady
    168
    +        })
    169
    +    }
    170
    +
    171
    +    function initWxData(data, flag) {
    172
    +        for(var d in data) {if (d in wxData) wxData[d] = data[d]}
    173
    +        if (flag) fixedWxData()
    174
    +    }
    175
    +
    176
    +    function changeWxData(key, value, flag) {
    177
    +        if (key in falDwxDataata) {wxData[key] = value}
    178
    +        if (flag) fixedWxData()
    179
    +    }
    180
    +
    181
    +    function fixedWxData() {
    182
    +        if ('undefined' !== typeof wxApiFun) wxApiFun()
    183
    +    }
    184
    +
    185
    +    // 5 图片接口
    186
    +    // 5.1 拍照、本地选图
    187
    +    var images = {
    188
    +        localIds: [],
    189
    +        serverIds: []
    190
    +    };
    191
    +    function chooseImage(count, directUpload, isShowProgressTips) {
    192
    +        if ('undefined' === typeof count) {count = 9}
    193
    +        if ('undefined' === typeof directUpload) {directUpload = false}
    194
    +        if ('undefined' === typeof isShowProgressTips) {isShowProgressTips = 1}
    195
    +        wx.chooseImage({
    196
    +            count: count, // 默认9
    197
    +            sizeType: ['original', 'compressed'], // 可以指定是原图还是压缩图,默认二者都有
    198
    +            sourceType: ['album', 'camera'], // 可以指定来源是相册还是相机,默认二者都有
    199
    +            success: function (res) {
    200
    +                var localIds = res.localIds; // 返回选定照片的本地ID列表,localId可以作为img标签的src属性显示图片
    201
    +                images.localIds = localIds;
    202
    +                // 判断是否直接上传
    203
    +                if (directUpload) {setTimeout(uploadImages(localIds, isShowProgressTips), 100)}
    204
    +                // 拍照、本地选图成功后的回调函数
    205
    +                if (JSWE.wxChooseImageSuccess) {JSWE.wxChooseImageSuccess(res)}
    206
    +            }
    207
    +        });
    208
    +    }
    209
    +
    210
    +    // 5.3 上传图片
    211
    +    function uploadImage(localId, isShowProgressTips) {
    212
    +        // 上传图片为异步处理,重复上传同一图片,返回的serverId也是不同的
    213
    +        wx.uploadImage({
    214
    +            localId: localId, // 需要上传的图片的本地ID,由chooseImage接口获得
    215
    +            isShowProgressTips: 1, // 默认为1,显示进度提示
    216
    +            success: function (res) {
    217
    +                var serverId = res.serverId; // 返回图片的服务器端ID
    218
    +                images.serverIds.push(serverId);
    219
    +                // 上传图片成功后的回调函数
    220
    +                if (JSWE.wxUploadImageSuccess) {JSWE.wxUploadImageSuccess(res)}
    221
    +            }
    222
    +        });
    223
    +    }
    224
    +
    225
    +    function uploadImages(localIds, isShowProgressTips) {
    226
    +        if ('undefined' === typeof localIds) {localIds = images.localIds}
    227
    +        if ('undefined' === typeof isShowProgressTips) {isShowProgressTips = 1}
    228
    +        images.serverIds = [];
    229
    +        for (var index in localIds) {uploadImage(localIds[index], isShowProgressTips)}
    230
    +    }
    231
    +
    232
    +    // 10 微信支付接口
    233
    +    // 10.1 发起一个支付请求
    234
    +    function chooseWXPay(wxpay_params) {
    235
    +        wx.chooseWXPay({
    236
    +            timestamp: wxpay_params.timeStamp, // 支付签名时间戳,注意微信jssdk中的所有使用timestamp字段均为小写。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
    237
    +            nonceStr: wxpay_params.nonceStr, // 支付签名随机串,不长于 32 位
    238
    +            package: wxpay_params.package, // 统一支付接口返回的prepay_id参数值,提交格式如:prepay_id=***)
    239
    +            signType: wxpay_params.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
    240
    +            paySign: wxpay_params.paySign, // 支付签名
    241
    +            success: function (res) {
    242
    +                // 支付成功后的回调函数
    243
    +                if (JSWE.wxPaySuccess) {JSWE.wxPaySuccess(res)}
    244
    +            }
    245
    +        })
    246
    +    }
    247
    +
    248
    +    // xx 微信原生企业红包接口
    249
    +    // xx.1 发起一个发送原生企业红包请求
    250
    +    function openEnterpriseRedPacket(wxredpack_params) {
    251
    +        wx.openEnterpriseRedPacket({
    252
    +            timeStamp: wxredpack_params.timeStamp, // 红包签名时间戳,注意原生企业红包接口timeStamp字段名需大写其中的S字符,而支付接口timeStamp字段名无需大写其中的S字符。但最新版的支付后台生成签名使用的timeStamp字段名需大写其中的S字符
    253
    +            nonceStr: wxredpack_params.nonceStr, // 红包签名随机串,不长于 32 位
    254
    +            package: encodeURIComponent(wxredpack_params.package), // 发放红包接口返回的prepay_id参数值,提交格式如:prepay_id=***)
    255
    +            signType: wxredpack_params.signType, // 签名方式,默认为'SHA1',使用新版支付需传入'MD5'
    256
    +            paySign: wxredpack_params.paySign, // 红包签名
    257
    +            success: function (res) {
    258
    +                // 发送原生企业红包成功后的回调函数
    259
    +                if (JSWE.wxEnterpriseRedPacketSuccess) {JSWE.wxEnterpriseRedPacketSuccess(res)}
    260
    +            }
    261
    +        })
    262
    +    }
    263
    +
    264
    +    var v = {
    265
    +        version: '1.0.5',
    266
    +
    267
    +        // Basic Vars
    268
    +        config: config,
    269
    +        wxData: wxData,
    270
    +        jsApiList: jsApiList,
    271
    +
    272
    +        // Weixin Function
    273
    +        isOpenInWeixin: isOpenInWeixin,
    274
    +        getWeixinVersion: getWeixinVersion,
    275
    +        isWeixinVersion: isWeixinVersion,
    276
    +
    277
    +        // Menu Function
    278
    +        hideOptionMenu: hideOptionMenu,
    279
    +        showOptionMenu: showOptionMenu,
    280
    +        closeWindow: closeWindow,
    281
    +
    282
    +        // Share Function
    283
    +        initWxData: initWxData,
    284
    +        changeWxData: changeWxData,
    285
    +        fixedWxData: fixedWxData,
    286
    +
    287
    +        // Image Function
    288
    +        images: images,
    289
    +        chooseImage: chooseImage,
    290
    +        uploadImage: uploadImage,
    291
    +        uploadImages: uploadImages,
    292
    +
    293
    +        // Pay Function
    294
    +        chooseWXPay: chooseWXPay,
    295
    +
    296
    +        // EnterpriseRedPacket Function
    297
    +        openEnterpriseRedPacket: openEnterpriseRedPacket
    298
    +    }
    299
    +    e.JSWE = e.V = v
    300
    +})(window)

    + 33 - 0
    tamron/urls.py

    @@ -0,0 +1,33 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +"""tamron URL Configuration
    4
    +
    5
    +The `urlpatterns` list routes URLs to views. For more information please see:
    6
    +    https://docs.djangoproject.com/en/1.8/topics/http/urls/
    7
    +Examples:
    8
    +Function views
    9
    +    1. Add an import:  from my_app import views
    10
    +    2. Add a URL to urlpatterns:  url(r'^$', views.home, name='home')
    11
    +Class-based views
    12
    +    1. Add an import:  from other_app.views import Home
    13
    +    2. Add a URL to urlpatterns:  url(r'^$', Home.as_view(), name='home')
    14
    +Including another URLconf
    15
    +    1. Add an import:  from blog import urls as blog_urls
    16
    +    2. Add a URL to urlpatterns:  url(r'^blog/', include(blog_urls))
    17
    +"""
    18
    +from django.conf.urls import include, url
    19
    +from django.contrib import admin
    20
    +
    21
    +from page import info_views, oauth_views, sale_views
    22
    +
    23
    +
    24
    +urlpatterns = [
    25
    +    url(r'^admin/', include(admin.site.urls)),
    26
    +    url(r'^api/', include('api.urls', namespace='api')),
    27
    +]
    28
    +
    29
    +urlpatterns += [
    30
    +    url(r'^page/clerk$', oauth_views.clerk_oauth, name='clerk_oauth'),  # 店员授权页面
    31
    +    url(r'^page/clerk/sale$', sale_views.clerk_sale_oauth, name='clerk_sale_oauth'),  # 店员销售授权页面
    32
    +    url(r'^page/clerk/info$', info_views.clerk_info_oauth, name='clerk_info_oauth'),  # 店员信息授权页面
    33
    +]

    BIN
    tamron/urls.pyc


    + 2 - 0
    tamron/uwsgi.bak/shutdown.sh

    @@ -0,0 +1,2 @@
    1
    +killall -9 uwsgi
    2
    +echo "2敏加油~~~!!!↖(^ω^)↗"

    + 2 - 0
    tamron/uwsgi.bak/startup.sh

    @@ -0,0 +1,2 @@
    1
    +nohup uwsgi --ini pai2.ini &>pai2.log &
    2
    +echo "Start Success !!!"

    + 27 - 0
    tamron/uwsgi.bak/tamron.ini

    @@ -0,0 +1,27 @@
    1
    +# tamron_uwsgi.ini file
    2
    +[uwsgi]
    3
    +
    4
    +# Django-related settings
    5
    +# the base directory (full path)
    6
    +chdir           = /home/paiai/work/tamron
    7
    +# Django's wsgi file
    8
    +module          = tamron.wsgi
    9
    +# the virtualenv (full path)
    10
    +# home            = /path/to/virtualenv
    11
    +
    12
    +# process-related settings
    13
    +# master
    14
    +master          = true
    15
    +# maximum number of worker processes
    16
    +processes       = 10
    17
    +# the socket (use the full path to be safe
    18
    +socket          = /home/paiai/work/tamron/tamron/uwsgi/tamron.sock
    19
    +# ... with appropriate permissions - may be needed
    20
    +chmod-socket    = 777
    21
    +# clear environment on exit
    22
    +vacuum          = true
    23
    +
    24
    +# 11: Resource temporarily unavailable
    25
    +reload-mercy    = 64
    26
    +max-requests    = 8192
    27
    +listen          = 4096

    + 35 - 0
    tamron/uwsgi.bak/tamron_nginx.conf

    @@ -0,0 +1,35 @@
    1
    +# tamron_nginx.conf
    2
    +
    3
    +# the upstream component nginx needs to connect to
    4
    +upstream pai2 {
    5
    +    # server unix:///home/paiai/work/tamron/tamron/uwsgi/tamron.sock; # for a file socket
    6
    +    server 127.0.0.1:8888; # for a web port socket (we'll use this first)
    7
    +}
    8
    +
    9
    +# configuration of the server
    10
    +server {
    11
    +    # the port your site will be served on
    12
    +    listen      80;
    13
    +    # the domain name it will serve for
    14
    +    server_name .tamron.xfoto.com.cn; # substitute your machine's IP address or FQDN
    15
    +    charset     utf-8;
    16
    +
    17
    +    # max upload size
    18
    +    client_max_body_size 75M;   # adjust to taste
    19
    +
    20
    +    # Django media
    21
    +    location /media  {
    22
    +        alias /home/paiai/work/tamron/media;  # your Django project's media files - amend as required
    23
    +    }
    24
    +
    25
    +    location /static {
    26
    +        alias /home/paiai/work/tamron/collect_static; # your Django project's static files - amend as required
    27
    +    }
    28
    +
    29
    +    # Finally, send all non-media requests to the Django server.
    30
    +    location / {
    31
    +        # uwsgi_pass  tamron;
    32
    +        proxy_pass  http://tamron;
    33
    +        include     /home/paiai/work/tamron/tamron/uwsgi/uwsgi_params; # the uwsgi_params file you installed
    34
    +    }
    35
    +}

    + 15 - 0
    tamron/uwsgi.bak/uwsgi_params

    @@ -0,0 +1,15 @@
    1
    +uwsgi_param	QUERY_STRING		$query_string;
    2
    +uwsgi_param	REQUEST_METHOD		$request_method;
    3
    +uwsgi_param	CONTENT_TYPE		$content_type;
    4
    +uwsgi_param	CONTENT_LENGTH		$content_length;
    5
    +
    6
    +uwsgi_param	REQUEST_URI		$request_uri;
    7
    +uwsgi_param	PATH_INFO		$document_uri;
    8
    +uwsgi_param	DOCUMENT_ROOT		$document_root;
    9
    +uwsgi_param	SERVER_PROTOCOL		$server_protocol;
    10
    +uwsgi_param	UWSGI_SCHEME		$scheme;
    11
    +
    12
    +uwsgi_param	REMOTE_ADDR		$remote_addr;
    13
    +uwsgi_param	REMOTE_PORT		$remote_port;
    14
    +uwsgi_param	SERVER_PORT		$server_port;
    15
    +uwsgi_param	SERVER_NAME		$server_name;

    + 17 - 0
    tamron/wsgi.py

    @@ -0,0 +1,17 @@
    1
    +"""
    2
    +WSGI config for tamron project.
    3
    +
    4
    +It exposes the WSGI callable as a module-level variable named ``application``.
    5
    +
    6
    +For more information on this file, see
    7
    +https://docs.djangoproject.com/en/1.8/howto/deployment/wsgi/
    8
    +"""
    9
    +
    10
    +import os
    11
    +
    12
    +from django.core.wsgi import get_wsgi_application
    13
    +
    14
    +
    15
    +os.environ.setdefault("DJANGO_SETTINGS_MODULE", "tamron.settings")
    16
    +
    17
    +application = get_wsgi_application()

    BIN
    tamron/wsgi.pyc


    + 0 - 0
    utils/__init__.py


    BIN
    utils/__init__.pyc


    + 0 - 0
    utils/error/__init__.py


    BIN
    utils/error/__init__.pyc


    + 62 - 0
    utils/error/errno_utils.py

    @@ -0,0 +1,62 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from StatusCode import BaseStatusCode, StatusCodeField
    4
    +
    5
    +
    6
    +class FranchiserStatusCode(BaseStatusCode):
    7
    +    """ 店员相关错误码 4001xx """
    8
    +    CHISER_NOT_FOUND = StatusCodeField(400001, 'Chiser Not Found', description=u'经销商不存在')
    9
    +
    10
    +
    11
    +class SaleclerkStatusCode(BaseStatusCode):
    12
    +    """ 店员相关错误码 4001xx """
    13
    +    CLERK_NOT_FOUND = StatusCodeField(400101, 'Clerk Not Found', description=u'店员不存在')
    14
    +    # 手机号
    15
    +    CLERK_PHONE_ALREADY_EXISTS = StatusCodeField(400105, 'Clerk Phone Already Exists', description=u'手机号已经存在')
    16
    +    # 状态
    17
    +    CLERK_ALREADY_NOT_UNVERIFIED = StatusCodeField(400110, 'Clerk Already Not Unverified', description=u'店员帐号已激活')
    18
    +    CLERK_NOT_ACTIVATED = StatusCodeField(400115, 'Clerk Not Activated', description=u'店员帐号未激活')
    19
    +
    20
    +
    21
    +class ProductModelStatusCode(BaseStatusCode):
    22
    +    """ 型号相关错误码 4010xx """
    23
    +    MODEL_NOT_FOUND = StatusCodeField(401001, 'Model Not Found', description=u'型号不存在')
    24
    +
    25
    +
    26
    +class ProductStatusCode(BaseStatusCode):
    27
    +    """ 产品相关错误码 4020xx """
    28
    +    PRODUCT_NOT_FOUND = StatusCodeField(402001, 'Product Not Found', description=u'产品不存在')
    29
    +    # 状态
    30
    +    PRODUCT_HAS_USED = StatusCodeField(402011, 'Product Has Used', description=u'产品已使用')
    31
    +
    32
    +
    33
    +class OrderStatusCode(BaseStatusCode):
    34
    +    """ 订单/支付相关错误码 4040xx """
    35
    +    WX_UNIFIED_ORDER_FAIL = StatusCodeField(404000, 'WX Unified Order Fail', description=u'微信统一下单失败')
    36
    +    WX_ORDER_NOT_FOUND = StatusCodeField(404001, 'WX Order Not Found', description=u'订单不存在')
    37
    +    WX_ORDER_NOT_PAY = StatusCodeField(404002, 'WX Order Not Pay', description=u'订单未支付')
    38
    +    WX_ORDER_PAYING = StatusCodeField(404003, 'WX Order Paying', description=u'订单支付中')
    39
    +    WX_ORDER_PAY_FAIL = StatusCodeField(404009, 'WX Order Pay Fail', description=u'微信支付失败')
    40
    +    SIGN_CHECK_FAIL = StatusCodeField(404010, 'Sign Check Fail', description=u'签名校验失败')
    41
    +    FEE_CHECK_FAIL = StatusCodeField(404011, 'FEE Check Fail', description=u'金额校验失败')
    42
    +    NO_DETAIL_PERMISSION = StatusCodeField(404015, 'No Detail Permission', description=u'无详情权限')
    43
    +    WX_ORDER_PAID_ALREADY_EXISTS = StatusCodeField(404020, 'WX Order Paid Already Exists', description=u'照片已购买')
    44
    +
    45
    +
    46
    +class PayStatusCode(BaseStatusCode):
    47
    +    """ 支付相关错误码 4041xx """
    48
    +
    49
    +
    50
    +class WithdrawStatusCode(BaseStatusCode):
    51
    +    """ 提现相关错误码 4042xx """
    52
    +    BALANCE_NOT_ENOUGH = StatusCodeField(404200, 'Balance Not Enough', description=u'提现金额不足')
    53
    +
    54
    +
    55
    +class MessageStatusCode(BaseStatusCode):
    56
    +    """ 消息相关错误码 4090xx """
    57
    +    MESSAGE_NOT_FOUND = StatusCodeField(409001, 'Message Not Found', description=u'消息不存在')
    58
    +
    59
    +
    60
    +class TokenStatusCode(BaseStatusCode):
    61
    +    """ 票据相关错误码 4090xx """
    62
    +    TOKEN_NOT_FOUND = StatusCodeField(409901, 'Token Not Found', description=u'票据不存在')

    BIN
    utils/error/errno_utils.pyc


    + 18 - 0
    utils/error/response_utils.py

    @@ -0,0 +1,18 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from django.http import JsonResponse
    4
    +from StatusCode import StatusCodeField
    5
    +
    6
    +
    7
    +def response_data(status_code=200, message=None, description=None, data={}, **kwargs):
    8
    +    return dict({
    9
    +        'status': status_code,
    10
    +        'message': message,
    11
    +        'description': description,
    12
    +        'data': data,
    13
    +    }, **kwargs)
    14
    +
    15
    +
    16
    +def response(status_code=200, message=None, description=None, data={}, **kwargs):
    17
    +    message, description = (message or status_code.message, description or status_code.description) if isinstance(status_code, StatusCodeField) else (message, description)
    18
    +    return JsonResponse(response_data(status_code, message, description, data, **kwargs), safe=False)

    BIN
    utils/error/response_utils.pyc


    + 0 - 0
    utils/redis/__init__.py


    BIN
    utils/redis/__init__.pyc


    + 6 - 0
    utils/redis/connect.py

    @@ -0,0 +1,6 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +from django.conf import settings
    4
    +
    5
    +
    6
    +r = settings.REDIS_CACHE

    BIN
    utils/redis/connect.pyc


    + 68 - 0
    utils/redis/rkeys.py

    @@ -0,0 +1,68 @@
    1
    +# -*- coding: utf-8 -*-
    2
    +
    3
    +# 唯一标识相关
    4
    +UUID_LIST = 'uuid:list'  # List,唯一标识列表
    5
    +
    6
    +# 用户相关
    7
    +PROFILE_INFO = 'profile:info:%s'  # STRING,用户信息,user_id
    8
    +
    9
    +# 导游相关
    10
    +TOUR_GUIDE_GROUP_GEO_INFO = 'tour:guide:group:geo:info:%s'  # ZSET,旅游团地理位置信息,group_id
    11
    +TOUR_GUIDE_GROUP_GEO_SUBMIT_DT = 'tour:guide:group:geo:submit:dt:%s'  # ZSET,旅游团地理位置最后上传时间,group_id
    12
    +TOUR_GUIDE_GROUP_CUR_SESSION = 'tour:guide:group:cur:session:%s'  # STRING,旅游团当前Session,group_id,导游设置集合时间的时候更新
    13
    +TOUR_GUIDE_GROUP_CUR_GATHER_INFO = 'tour:guide:group:cur:gather:info:%s'  # STRING,旅游团当前Session,group_id,导游设置集合时间的时候更新
    14
    +TOUR_GUIDE_GROUP_USER_GEO_LIST = 'tour:guide:group:user:geo:list:%s:%s:%s'  # LIST,旅游团当前用户地理位置列表,group_id、session_id、user_id
    15
    +
    16
    +TOUR_GUIDE_GROUP_USER_OWN = 'tour:guide:group:user:own:%s'  # STRING,导游当前拥有的旅行团,user_id,导游创建旅行团的时候更新
    17
    +TOUR_GUIDE_GROUP_USER_BELONG = 'tour:guide:group:user:belong:%s'  # STRING,用户当前所属旅行团,user_id,用户加入旅行团的时候更新
    18
    +
    19
    +# 群组相关
    20
    +GROUP_INFO = 'group:info:%s'  # STRING,群组信息,group_id
    21
    +
    22
    +# 群组用户相关
    23
    +GROUP_USERS_INFO = 'group:users:info:%s'  # STRING,群组用户信息,group_id
    24
    +GROUP_USERS_KV_INFO = 'group:users:kv:info:%s'  # STRING,群组用户信息,group_id
    25
    +GROUP_USERS_APPLYING_SET = 'group:users:applying:set:%s'  # SET,群组用户申请集合,group_id
    26
    +GROUP_USERS_PASSED_SET = 'group:users:passed:set:%s'  # SET,群组用户通过集合,group_id
    27
    +GROUP_USERS_REFUSED_SET = 'group:users:refused:set:%s'  # SET,群组用户拒绝集合,group_id
    28
    +GROUP_USERS_DELETED_SET = 'group:users:deleted:set:%s'  # SET,群组用户移除集合,group_id
    29
    +GROUP_USERS_QUIT_SET = 'group:users:quit:set:%s'  # SET,群组用户退出集合,group_id
    30
    +
    31
    +# 群组照片相关
    32
    +GROUP_PHOTO_DATA = 'group:photo:data:%s'  # STRING,群组数据记录,group_id
    33
    +GROUP_PHOTO_THUMB_UP = 'group:photo:thumb:up:%s:%s'  # STRING,群组照片用户点赞记录,photo_id、user_id
    34
    +GROUP_PHOTO_COMMENT_LIST = 'group:photo:comment:list:%s'  # STRING,群组照片用户评论列表,photo_id
    35
    +GROUP_PHOTO_THUMB_UP_LIST = 'group:photo:thumb:up:list:%s'  # STRING,群组照片用户点赞列表,photo_id
    36
    +GROUP_PHOTO_WATCHER_SET = 'group:photo:watcher:set:%s'  # SET,群组照片用户关注集合,photo_id,关注即评论点赞
    37
    +GROUP_LAST_PHOTO_PK = 'group:last:photo:pk:%s'  # STRING,群组最后一张照片PK,group_id
    38
    +
    39
    +# 摄影师照片相关
    40
    +LENSMAN_PHOTO_ORDER_RECORD = 'lensman:photo:order:record:%s:%s'  # STRING,摄影师照片购买记录,photo_id、user_id
    41
    +
    42
    +# 摄影师简报相关
    43
    +# 收入
    44
    +TOTAL_INCOME = 'total:income:%s:%s'  # STRING,总收入,user_id、photo_type
    45
    +WEEK_INCOME = 'week:income:%s:%s:%s'  # STRING,周收入,user_id、photo_type、Week.thisweek().isoformat()
    46
    +TODAY_INCOME = 'today:income:%s:%s:%s'  # STRING,日收入,user_id、photo_type、tc.local_string(format='%Y%m%d')
    47
    +# 上传
    48
    +TODAY_UPLOAD_PHOTO_AMOUNT = 'today:upload:photo:amount:%s:%s'  # STRING,日上传照片数量,user_id、tc.local_string(format='%Y%m%d')
    49
    +# 售出
    50
    +WEEK_SOLD = 'week:sold:%s:%s:%s'  # STRING,周售出,user_id、photo_type、Week.thisweek().isoformat()
    51
    +
    52
    +# 摄影师定价相关
    53
    +LENSMAN_PHOTO_PRICE_FIXED = 'lensman:photo:price:fixed:%s'  # STRING,摄影师照片定价(单位:分),user_id
    54
    +
    55
    +# 系统消息相关
    56
    +SYSTEM_MESSAGE_READ_INFO = 'system:message:read:info:%s'  # STRING,系统消息读取信息,user_id
    57
    +SYSTEM_MESSAGE_DELETED_INFO = 'system:message:deleted:info:%s'  # STRING,系统消息删除信息,user_id
    58
    +
    59
    +# 游客入口相关
    60
    +GUEST_ENTRANCE_CONTROL_INFO = 'guest:entrance:control:info:%s'  # STRING,游客入口控制信息,src
    61
    +
    62
    +# APP 相关
    63
    +LATEST_APP_INFO = 'latest:app:info:%s'  # STRING,最新 APP 信息,src
    64
    +APP_SETTINGS_INFO = 'app:settings:info:%s:%s:%s'  # STRING,APP 设置信息,platform、channel、version
    65
    +APP_PATCH_INFO = 'app:patch:info:%s:%s:%s'  # STRING,APP 补丁信息,platform、version、src
    66
    +
    67
    +# BOX 相关
    68
    +BOX_PROGRAM_VERSION_INFO = 'box:program:version:info'  # STRING,BOX 程序版本信息

    adminSystem - Gogs: Go Git Service

    Nav apraksta

    LICENSE 1.1KB

      The MIT License (MIT) Copyright (c) 2015-2017, Jon Schlinkert. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.