Procházet zdrojové kódy

入库申请完成,开始编写组盘入库

flower_mr před 2 měsíci
rodič
revize
9e3420b089
39 změnil soubory, kde provedl 1210 přidání a 13700 odebrání
  1. binární
      bound/__pycache__/models.cpython-38.pyc
  2. 0 0
      container/__init__.py
  3. 3 0
      container/admin.py
  4. 6 0
      container/apps.py
  5. 0 0
      container/migrations/__init__.py
  6. 3 0
      container/models.py
  7. 3 0
      container/tests.py
  8. 3 0
      container/views.py
  9. 77 0
      data_base/import_product.py
  10. 192 0
      data_base/product.csv
  11. binární
      db.sqlite3
  12. 0 6402
      logs/error.log
  13. 1 7145
      logs/server.log
  14. 113 21
      templates/src/pages/inbound/asn.vue
  15. 491 0
      templates/src/pages/warehouse/product.vue
  16. 3 1
      templates/src/pages/warehouse/warehouse.vue
  17. 6 0
      templates/src/router/routes.js
  18. binární
      warehouse/__pycache__/admin.cpython-38.pyc
  19. binární
      warehouse/__pycache__/filter.cpython-38.pyc
  20. binární
      warehouse/__pycache__/models.cpython-38.pyc
  21. binární
      warehouse/__pycache__/serializers.cpython-38.pyc
  22. binární
      warehouse/__pycache__/urls.cpython-38.pyc
  23. binární
      warehouse/__pycache__/views.cpython-38.pyc
  24. 2 1
      warehouse/admin.py
  25. 15 2
      warehouse/filter.py
  26. 115 1
      warehouse/migrations/0001_initial.py
  27. 0 91
      warehouse/migrations/0002_boundbslistmodel_boundcodetypelistmodel_and_more.py
  28. 0 32
      warehouse/migrations/0003_boundstatuslistmodel.py
  29. binární
      warehouse/migrations/__pycache__/0001_initial.cpython-38.pyc
  30. binární
      warehouse/migrations/__pycache__/0002_boundbslistmodel_boundcodetypelistmodel_and_more.cpython-38.pyc
  31. binární
      warehouse/migrations/__pycache__/0003_boundstatuslistmodel.cpython-38.pyc
  32. binární
      warehouse/migrations/__pycache__/0004_productlistmodel.cpython-38.pyc
  33. binární
      warehouse/migrations/__pycache__/0005_alter_productlistmodel_product_code.cpython-38.pyc
  34. binární
      warehouse/migrations/__pycache__/0006_alter_productlistmodel_product_code.cpython-38.pyc
  35. binární
      warehouse/migrations/__pycache__/0007_remove_productlistmodel_create_time_and_more.cpython-38.pyc
  36. 16 1
      warehouse/models.py
  37. 55 1
      warehouse/serializers.py
  38. 9 0
      warehouse/urls.py
  39. 97 2
      warehouse/views.py

binární
bound/__pycache__/models.cpython-38.pyc


+ 0 - 0
container/__init__.py


+ 3 - 0
container/admin.py

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

+ 6 - 0
container/apps.py

@@ -0,0 +1,6 @@
+from django.apps import AppConfig
+
+
+class ContainerConfig(AppConfig):
+    default_auto_field = 'django.db.models.BigAutoField'
+    name = 'container'

+ 0 - 0
container/migrations/__init__.py


+ 3 - 0
container/models.py

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

+ 3 - 0
container/tests.py

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

+ 3 - 0
container/views.py

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

+ 77 - 0
data_base/import_product.py

@@ -0,0 +1,77 @@
+import sqlite3
+import csv
+import time
+import os
+
+# 记录开始时间
+start_time = time.time()
+
+# 连接数据库(动态获取数据库路径)
+db_path = os.path.abspath('../db.sqlite3')
+print(f"[{time.strftime('%H:%M:%S')}] 正在连接数据库: {db_path}")
+
+try:
+    conn = sqlite3.connect(db_path)
+    cursor = conn.cursor()
+    # 在插入前清空表
+    cursor.execute("DELETE FROM product;")
+    print(f"[{time.strftime('%H:%M:%S')}] ✅ 数据库连接成功")
+
+    # 读取CSV文件
+    csv_file = 'product.csv'
+    print(f"\n[{time.strftime('%H:%M:%S')}] 开始导入文件: {csv_file}")
+    
+  
+    with open(csv_file, 'r', encoding='utf-8') as f:
+
+        reader = csv.reader(f)
+        
+        # 读取标题行
+        try:
+            header = next(reader)
+            num_columns = len(header)
+            print(f"[{time.strftime('%H:%M:%S')}] 检测到 {num_columns} 列 | 标题: {', '.join(header)}")
+        
+        except StopIteration:
+            print("❌ 错误:CSV文件为空或格式不正确")
+            exit()
+
+        # 准备SQL语句
+        placeholders = ', '.join(['?'] * num_columns)
+        sql = f"INSERT INTO product VALUES ({placeholders})"
+        print(f"[{time.strftime('%H:%M:%S')}] 生成SQL语句: {sql}\n")
+
+        # 插入数据
+        total_rows = 0
+        for i, row in enumerate(reader, 1):
+            # 关键修改:将空白值转换为0
+            processed_row = [
+                0 if str(cell).strip() == '' else cell  # 空白转0,保留非空值
+                for cell in row
+            ]
+            cursor.execute(sql, processed_row)
+            total_rows += 1
+            
+            # 每100行提示进度
+            if i % 10 == 0:
+                print(f"[{time.strftime('%H:%M:%S')}] 已插入 {i} 行...", end='\r')
+        
+        # 提交事务
+        conn.commit()
+        print(f"\n[{time.strftime('%H:%M:%S')}] ✅ 数据插入完成,共 {total_rows} 行")
+
+except FileNotFoundError:
+    print(f"❌ 错误:CSV文件不存在,当前搜索路径: {os.path.abspath(csv_file)}")
+except sqlite3.Error as e:
+    print(f"❌ 数据库错误: {str(e)}")
+    conn.rollback()
+except Exception as e:
+    print(f"❌ 发生异常: {str(e)}")
+finally:
+    if 'conn' in locals():
+        conn.close()
+        print(f"[{time.strftime('%H:%M:%S')}] 数据库连接已关闭")
+
+# 计算总耗时
+end_time = time.time()
+print(f"\n总耗时: {end_time - start_time:.2f} 秒")

+ 192 - 0
data_base/product.csv

@@ -0,0 +1,192 @@
+id,product_code,product_name,product_std,creater,is_delete
+1,D/DA06,地奥司明,STP,first,0
+2,DAP01,地奥司明,STP,first,0
+3,DAP02,地奥司明,STP,first,0
+4,DAP04,地奥司明,STP,first,0
+5,DAP05,地奥司明,STP,first,0
+6,DAP06,地奥司明,STP,first,0
+7,DAP08,柑橘黄酮,STP,first,0
+8,DAP09,地奥司明,STP,first,0
+9,DAP10,地奥司明,STP,first,0
+10,DAP11,地奥司明,STP,first,0
+11,DAP08,柑橘黄酮,STP,first,0
+12,DBP08,柑橘黄酮,STP,first,0
+13,DBP01,地奥司明微粉,STP,first,0
+14,DBP04,地奥司明微粉,STP,first,0
+15,DBP05,地奥司明微粉,STP,first,0
+16,DBP06,地奥司明微粉,STP,first,0
+17,DBP09,地奥司明微粉,STP,first,0
+18,DBP10,地奥司明微粉,STP,first,0
+19,DBP11,地奥司明微粉,STP,first,0
+20,DBP12,地奥司明微粉,STP,first,0
+21,DFF03,地奥司明A/SG,STP,first,0
+22,DBP07,MPFF,STP,first,0
+23,DAF01,地奥司明,STP,first,0
+24,DAF02,地奥司明,STP,first,0
+25,DAF03,地奥司明,STP,first,0
+26,DAF04,地奥司明,STP,first,0
+27,DAF05,地奥司明,STP,first,0
+28,DBF01,地奥司明微粉,STP,first,0
+29,DBF02,地奥司明微粉,STP,first,0
+30,DBF03,地奥司明微粉,STP,first,0
+31,DBF04,地奥司明微粉,STP,first,0
+32,DBF05,地奥司明微粉,STP,first,0
+33,D/RAF01,芦丁,STP,first,0
+34,D/RCF01,芦丁,STP,first,0
+35,D/RDF01,芦丁,STP,first,0
+36,D/RDF02,芦丁,STP,first,0
+37,D/RF02,芦丁,STP,first,0
+38,D/RDP01,芦丁,STP,first,0
+39,D/RI01,芦丁(S),STP,first,0
+40,RDP01,芦丁(S),STP,first,0
+41,RDP02,芦丁(S),STP,first,0
+42,RF02,芦丁A,STP,first,0
+43,RF04,芦丁E,STP,first,0
+44,D/TAF01,曲克芦丁,STP,first,0
+45,D/UAF01,L-鼠李糖,STP,first,0
+46,DHF02,香叶木素,STP,first,0
+47,DHF02,香叶木素,STP,first,0
+48,D/NAF01,新橙皮苷,STP,first,0
+49,D/NCF01,柚苷,STP,first,0
+50,D/NDF01,柚皮苷二氢查耳酮,STP,first,0
+51,CCF01,鹰嘴豆蛋白,STP,first,0
+52,PBF01,根皮素,STP,first,0
+53,PAF01,普鲁宁,STP,first,0
+54,EG01,蛋黄粉(脱脂),STP,first,0
+55,GAF01,染料木素,STP,first,0
+56,HDF01,橙皮素,STP,first,0
+57,GBF01,葡糖基芦丁(AGR),STP,first,0
+58,D/EG02,(鸡)蛋黄粉,STP,first,0
+59,EG02,(鸡)蛋黄粉,STP,first,0
+60,RHF01,白藜芦醇,STP,first,0
+61,LBF01,左旋多巴,STP,first,0
+62,BDF01,苦荞黄酮,STP,first,0
+63,SBF01,甜橙皮提取物,STP,first,0
+64,D/SBF01,甜橙皮提取物,STP,first,0
+65,LCF01,圣草次苷,STP,first,0
+66,AAP01,青蒿素,STP,first,0
+67,ABP01,双氢青蒿素,STP,first,0
+68,ADP01,蒿甲醚,STP,first,0
+69,ACP01,青蒿琥酯,STP,first,0
+70,DAF04,地奥司明,F-STP,first,0
+71,DCF02,地奥司明:橙皮苷(90:10),F-STP,first,0
+72,DCF03,地奥司明:橙皮苷(90:10),F-STP,first,0
+73,DCF04,地奥司明:橙皮苷(90:10),F-STP,first,0
+74,DCF06,地奥司明:橙皮苷(90:10),F-STP,first,0
+75,DDF02,地奥司明:橙皮苷(90:10)微粉,F-STP,first,0
+76,DDF03,地奥司明:橙皮苷(90:10)微粉,F-STP,first,0
+77,DGF01,地奥司明:橙皮苷(90:10)颗粒,F-STP,first,0
+78,LDF01,柠檬黄酮,F-STP,first,0
+79,QHF01,二氢槲皮素,F-STP,first,0
+80,QM02,芦丁水解中和浓缩液,F-STP,first,0
+81,GBF01,葡萄柚黄酮,F-STP,first,0
+82,GBF02,葡萄柚黄酮,F-STP,first,0
+83,GBF03,葡萄柚黄酮,F-STP,first,0
+84,BAF01,盐酸小檗碱,F-STP,first,0
+85,BAF02,盐酸小檗碱,F-STP,first,0
+86,BAF03,盐酸小檗碱,F-STP,first,0
+87,BBF04,盐酸小檗碱颗粒,F-STP,first,0
+88,BBF05,盐酸小檗碱颗粒,F-STP,first,0
+89,BCF03,高密度盐酸小檗碱,F-STP,first,0
+90,D/NBF05,新甲基橙皮苷二氢查耳酮,F-STP,first,0
+91,NBF01,新甲基橙皮苷二氢查耳酮,F-STP,first,0
+92,NBF05,新甲基橙皮苷二氢查耳酮,F-STP,first,0
+93,D/QAF01,二水槲皮素,F-STP,first,0
+94,D/QAF03,二水槲皮素,F-STP,first,0
+95,D/QAF08,二水槲皮素,F-STP,first,0
+96,D/QBF03,二水槲皮素颗粒,F-STP,first,0
+97,D/QDF02,无水槲皮素,F-STP,first,0
+98,D/QDF02,无水槲皮素(HM-02),F-STP,first,0
+99,D/QDF03,无水槲皮素,F-STP,first,0
+100,D/QDF04,无水槲皮素,F-STP,first,0
+101,D/QEF01,无水槲皮素颗粒,F-STP,first,0
+102,QAF01,二水槲皮素,F-STP,first,0
+103,QAF03,二水槲皮素,F-STP,first,0
+104,QAF05,二水槲皮素,F-STP,first,0
+105,QAF08,二水槲皮素,F-STP,first,0
+106,QBF03,二水槲皮素颗粒,F-STP,first,0
+107,QCF02,二水高密度槲皮素,F-STP,first,0
+108,QCF03,二水高密度槲皮素,F-STP,first,0
+109,QCF05,二水高密度槲皮素,F-STP,first,0
+110,QCF06,二水高密度槲皮素,F-STP,first,0
+111,QDF02,无水槲皮素(HM-02),F-STP,first,0
+112,QDF02,无水槲皮素,F-STP,first,0
+113,QDF03,无水槲皮素,F-STP,first,0
+114,QDF04,无水槲皮素,F-STP,first,0
+115,QDF05,无水槲皮素,F-STP,first,0
+116,QEF01,无水槲皮素颗粒,F-STP,first,0
+117,QEF02,无水槲皮素颗粒,F-STP,first,0
+118,QEF03,无水槲皮素颗粒,F-STP,first,0
+119,QEF04,无水槲皮素颗粒,F-STP,first,0
+120,QFF02,无水高密度槲皮素,F-STP,first,0
+121,QFF04,无水高密度槲皮素,F-STP,first,0
+122,QGF01,槐树花浸膏,F-STP,first,0
+123,RGF01,白藜芦醇颗粒,F-STP,first,0
+124,D/IAF01,异槲皮苷,F-STP,first,0
+125,D/IAF02,异槲皮苷,F-STP,first,0
+126,QHF01,二氢槲皮素,F-STP,first,0
+127,IAF01,异槲皮苷,F-STP,first,0
+128,IAF02,异槲皮苷,F-STP,first,0
+129,HAF01,橙皮苷,F-STP,first,0
+130,HAF02,橙皮苷,F-STP,first,0
+131,HAF03,橙皮苷,F-STP,first,0
+132,HAF04,橙皮苷,F-STP,first,0
+133,HBF01,橙皮苷微粉,F-STP,first,0
+134,HBF02,橙皮苷微粉,F-STP,first,0
+135,HBF03,橙皮苷微粉,F-STP,first,0
+136,HBP01,橙皮苷微粉,F-STP,first,0
+137,HCF01,橙皮苷颗粒,F-STP,first,0
+138,HCF02,橙皮苷颗粒,F-STP,first,0
+139,HCF03,橙皮苷颗粒,F-STP,first,0
+140,HAF01,橙皮苷,F-STP,first,0
+141,CAF01,枳实黄酮,F-STP,first,0
+142,CAF02,枳实黄酮,F-STP,first,0
+143,CAF03,枳实黄酮,F-STP,first,0
+144,CAF04,枳实黄酮,F-STP,first,0
+145,CAF05,枳实黄酮,F-STP,first,0
+146,CAF06,枳实黄酮,F-STP,first,0
+147,CAF07,枳实黄酮,F-STP,first,0
+148,CAF08,枳实黄酮,F-STP,first,0
+149,CBF01,枳实黄酮颗粒,F-STP,first,0
+150,CBF02,枳实黄酮颗粒,F-STP,first,0
+151,CBF03,枳实黄酮颗粒,F-STP,first,0
+152,RI01,芦丁(S),F-STP,first,0
+153,RI02,芦丁(S),F-STP,first,0
+154,TAF01,曲克芦丁,F-STP,first,0
+155,TAF03,曲克芦丁,F-STP,first,0
+156,TAF04,曲克芦丁,F-STP,first,0
+157,TBF01,曲克芦丁,F-STP,first,0
+158,RFF01,水溶性芦丁,F-STP,first,0
+159,RAF01,芦丁,F-STP,first,0
+160,RCF01,芦丁,F-STP,first,0
+161,RDF01,芦丁,F-STP,first,0
+162,RDF02,芦丁,F-STP,first,0
+163,RDF03,芦丁,F-STP,first,0
+164,RDF04,芦丁,F-STP,first,0
+165,RDF05,芦丁,F-STP,first,0
+166,REF01,芦丁颗粒,F-STP,first,0
+167,NCF01,柚苷,F-STP,first,0
+168,MBF01,橙皮苷甲基查耳酮,F-STP,first,0
+169,HDF01,橙皮素,F-STP,first,0
+170,NDF01,柚皮苷二氢查耳酮,F-STP,first,0
+171,NGF01,柚皮素,F-STP,first,0
+172,NAF01,新橙皮苷,F-STP,first,0
+173,NAF02,新橙皮苷,F-STP,first,0
+174,DHF01,香叶木素,F-STP,first,0
+175,DHF02,香叶木素,F-STP,first,0
+176,DFF01,地奥司明香叶木素颗粒,F-STP,first,0
+177,DFF02,地奥司明香叶木素颗粒,F-STP,first,0
+178,DEF01,地奥司明颗粒,F-STP,first,0
+179,DEF02,地奥司明颗粒,F-STP,first,0
+180,DEF03,地奥司明颗粒,F-STP,first,0
+181,DEF04,地奥司明颗粒,F-STP,first,0
+182,DFF03,地奥司明A/SG,F-STP,first,0
+183,HFF01,柑橘提取物,F-STP,first,0
+184,D/UAF01,L-鼠李糖,F-STP,first,0
+185,UAF01,L-鼠李糖,F-STP,first,0
+186,NFF01,柚苷颗粒,F-STP,first,0
+187,LUF01,木犀草素,F-STP,first,0
+188,GAF01,染料木素,F-STP,first,0
+189,NGF01,柚皮苷,F-STP,first,0
+190,LCF01,圣草次苷,F-STP,first,0
+191,FAF01,漆黄素,F-STP,first,0

binární
db.sqlite3


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 0 - 6402
logs/error.log


Rozdílová data souboru nebyla zobrazena, protože soubor je příliš velký
+ 1 - 7145
logs/server.log


+ 113 - 21
templates/src/pages/inbound/asn.vue

@@ -19,10 +19,10 @@
           <q-space />
           <div class="flex items-center">
 
-            <q-input outlined rounded dense debounce="300" color="primary" v-model="filter" :placeholder="$t('search')"
+            <q-input outlined rounded dense debounce="200" color="primary" v-model="filter" :placeholder="'输入名称搜索'"
               @input="getSearchList()" @keyup.enter="getSearchList()">
               <template v-slot:append>
-                <q-icon name="search" @click="getSearchList()" />
+                <q-icon name="search" />
               </template>
             </q-input>
           </div>
@@ -266,15 +266,40 @@
           </q-btn>
         </q-bar>
         <q-card-section style="max-height: 325px; width: 400px" class="scroll">
-          <!-- <q-select dense outlined square v-model="newBatchFormData.goods_code"
-           :label="'物料编码'" autofocus 
-            :options="goods_code_list" option-label="label" option-value="value" emit-value map-options
-            transition-show="scale"
-            transition-hide="scale"
-            :rules="[val => (val && val.length > 0) || error1]" /> -->
-          <q-input dense outlined square v-model="newBatchFormData.goods_code" :label="'物料编码'" 
-            :rules="[val => (val && val.length > 0) || error1]" />
-          <q-input dense outlined square v-model="newBatchFormData.goods_desc" :label="'货物描述'" 
+          <div class="text-h6 q-mb-md">{{ "批次信息" }}
+
+            
+        
+          </div>
+          <div class="row q-gutter-x-md">
+              <div class="col column q-gutter-y-md">
+                <q-select dense outlined square v-model="newBatchFormData.goods_code"
+                  :label="'物料编码'"  
+                    :options="product_list" option-label="value" option-value="value" emit-value map-options
+                    transition-show="scale"
+                    transition-hide="scale"
+                    :rules="[val => (val && val.length > 0) || error1]" />
+
+              </div>
+              <div class="col column q-gutter-y-md">
+                <q-input outlined  dense  color="primary" v-model="product_filter" :placeholder="'搜索名称'" autofocus
+                    @input="getProductSearchList()" @keyup.enter="getProductSearchList()">
+                  <template v-slot:append>
+                    <q-icon name="search" />
+                  </template>
+                </q-input>
+              </div>
+          </div>
+          <q-select dense outlined square v-model="newBatchFormData.goods_code"
+                  :label="'物料'"  
+                    :options="product_list" option-label="label" option-value="value" emit-value map-options  :readonly=true
+                    transition-show="scale"
+                    transition-hide="scale"
+                    :rules="[val => (val && val.length > 0) || error1]" />
+
+
+         
+          <q-input dense outlined square v-model="newBatchFormData.goods_desc" :label="'名称/备注'" 
             :rules="[val => (val && val.length > 0) || error1]" />
           <q-input dense outlined square v-model.number="newBatchFormData.goods_weight" :label="'单重'" type="number"
             :rules="[val => (val && val > 0) || error1]" />
@@ -397,7 +422,7 @@
 import { getauth, postauth, putauth, deleteauth } from 'boot/axios_request'
 
 import { date, exportFile, LocalStorage } from 'quasar'
-import Warehouse from '../warehouse/warehouse.vue'
+
 
 
 export default {
@@ -444,6 +469,8 @@ export default {
       bound_department_map:[],
       bound_status_list:[],
       bound_status_map:[],
+      product_list:[],
+      product_map:[],
 
       columns: [
         { name :'detail',label:'详情', field: 'detail', align: 'center'},
@@ -458,6 +485,7 @@ export default {
         { name: 'action', label: '操作', align: 'center' }
       ],
       filter: '',
+      product_filter: '',
       pagination: {
         page: 1,
         rowsPerPage: 11
@@ -468,6 +496,7 @@ export default {
 
       },
       newBatchFormData: {},
+      newDetailFormData:{},
       editid: 0,
       editFormData: {
 
@@ -554,6 +583,49 @@ export default {
       this.getSearchList(this.current)
     },
 
+    getProductSearchList()
+    {
+      var _this = this
+      _this.loading = true
+      const params = {
+        product_name__icontains: _this.product_filter,
+        max_page:1000
+      }
+      const queryParams = new URLSearchParams({
+        ...params
+      })
+      console.log(queryParams)
+      // 过滤空值参数
+      Array.from(queryParams.entries()).forEach(([key, value]) => {
+        if (value === '' || value === null || value === undefined) {
+          queryParams.delete(key)
+        }
+      })
+      console.log(`warehouse/product/?${queryParams}`)
+      getauth(`warehouse/product/?${queryParams}`)
+        .then(res => {
+          _this.product_list = res.results.map(item => ({
+          label: item.product_name,
+          value: item.product_code
+        }))
+        _this.product_map = res.results.reduce((acc, item) => {
+          acc[item.product_code] = item.product_name;
+          return acc;
+        }, {});
+        })
+        .catch(err => {
+          _this.$q.notify({
+            message: err.detail,
+            icon: 'close',
+            color: 'negative'
+          })
+        })
+        .finally(() => {
+          _this.loading = false
+        })
+    },
+    
+
     // 带搜索条件加载
     getSearchList(page = 1) {
       this.current = page
@@ -688,14 +760,33 @@ export default {
 
       postauth('bound/batch/', _this.newBatchFormData)
         .then(res => {
-          _this.getSearchList()
-          _this.newBatchCancel()
           if (res.status_code != 500) {
-            _this.$q.notify({
-              message: '成功新增数据',
-              icon: 'check',
-              color: 'green'
-            })
+            _this.newDetailFormData.bound_batch = res.id
+            _this.newDetailFormData.creater =   _this.login_name
+        
+
+            postauth('bound/detail/', _this.newDetailFormData)
+            .then(
+                res => {
+                  if (res.status_code != 500) {
+                    _this.detailData(_this.newDetailFormData)
+
+                    _this.$q.notify({
+                      message: '成功新增数据',
+                      icon: 'check',
+                      color: 'green'
+                    })
+                  }
+                },
+                err => {
+                  _this.$q.notify({
+                    message: err.detail,
+                    icon: 'close',
+                    color: 'negative'
+                  })
+                }
+            )
+     
           }
         })
         .catch(err => {
@@ -721,8 +812,9 @@ export default {
     addbatch(bound_number) {
       var _this = this
       _this.newBatchForm = true
-      _this.newBatchFormData = {
-        bound_number: bound_number,
+      _this.newDetailFormData = {
+        id: bound_number,
+        bound_list: bound_number,
         
       }
     },

+ 491 - 0
templates/src/pages/warehouse/product.vue

@@ -0,0 +1,491 @@
+<template>
+    <div>
+      <transition appear enter-active-class="animated fadeIn">
+        <q-table class="my-sticky-header-column-table shadow-24" :data="table_list" row-key="id" :separator="separator"
+          :loading="loading" :filter="filter" :columns="columns" hide-bottom :pagination.sync="pagination"
+          no-data-label="No data" no-results-label="No data you want" :table-style="{ height: height }" flat bordered>
+          <template v-slot:top>
+            <q-btn-group push>
+              <q-btn :label="$t('new')" icon="add" @click="newFormCheck()">
+                <q-tooltip content-class="bg-amber text-black shadow-4" :offset="[10, 10]"
+                  content-style="font-size: 12px">
+                  {{ $t('newtip') }}
+                </q-tooltip>
+              </q-btn>
+              <q-btn :label="$t('refresh')" icon="refresh" @click="reFresh()">
+                <q-tooltip content-class="bg-amber text-black shadow-4" :offset="[10, 10]"
+                  content-style="font-size: 12px">
+                  {{ $t('refreshtip') }}
+                </q-tooltip>
+              </q-btn>
+            </q-btn-group>
+            <q-space />
+          </template>
+          <template v-slot:body="props">
+            <q-tr :props="props">
+
+                
+              <template v-if="props.row.id === editid">
+                <q-td key="product_std" :props="props">
+                  <q-input dense outlined square v-model="editFormData.product_std"
+                    :label="'产品标准'" autofocus
+                    :rules="[val => val && val.length > 0 || error1]" />
+                </q-td>
+              </template>
+              <template v-else-if="props.row.id !== editid">
+                <q-td key="product_std" :props="props">
+                  {{ props.row.product_std }}
+                </q-td>
+              </template>
+
+              <template v-if="props.row.id === editid">
+                <q-td key="product_code" :props="props">
+                  <q-input dense outlined square v-model="editFormData.product_code"
+                    :label="'产品代码'" autofocus
+                    :rules="[val => val && val.length > 0 || error0]" />
+                </q-td>
+              </template>
+              <template v-else-if="props.row.id !== editid">
+                <q-td key="product_code" :props="props">
+                  {{ props.row.product_code }}
+                </q-td>
+              </template>
+
+              <template v-if="props.row.id === editid">
+                <q-td key="product_name" :props="props">
+                  <q-input dense outlined square v-model="editFormData.product_name"
+                    :label="'产品名称'" autofocus
+                    :rules="[val => val && val.length > 0 || error1]" />
+                </q-td>
+              </template>
+              <template v-else-if="props.row.id !== editid">
+                <q-td key="product_name" :props="props">
+                  {{ props.row.product_name }}
+                </q-td>
+              </template>
+
+           
+     
+
+              <q-td key="creater" :props="props">
+                {{ props.row.creater }}
+              </q-td>
+              <q-td key="create_time" :props="props">
+                {{ props.row.create_time }}
+              </q-td>
+              <q-td key="update_time" :props="props">
+                {{ props.row.update_time }}
+              </q-td>
+              <template v-if="!editMode">
+                <q-td key="action" :props="props" style="width: 100px">
+                  <q-btn round flat push color="purple" icon="edit" @click="editData(props.row)">
+                    <q-tooltip content-class="bg-amber text-black shadow-4" :offset="[10, 10]"
+                      content-style="font-size: 12px">
+                      {{ $t('edit') }}
+                    </q-tooltip>
+                  </q-btn>
+                  <q-btn round flat push color="dark" icon="delete" @click="deleteData(props.row.id)">
+                    <q-tooltip content-class="bg-amber text-black shadow-4" :offset="[10, 10]"
+                      content-style="font-size: 12px">
+                      {{ $t('delete') }}
+                    </q-tooltip>
+                  </q-btn>
+
+
+                </q-td>
+              </template>
+              <template v-else-if="editMode">
+                <template v-if="props.row.id === editid">
+                  <q-td key="action" :props="props" style="width: 100px">
+                    <q-btn round flat push color="secondary" icon="check" @click="editDataSubmit()">
+                      <q-tooltip content-class="bg-amber text-black shadow-4" :offset="[10, 10]"
+                        content-style="font-size: 12px">
+                        {{ $t('confirmedit') }}
+                      </q-tooltip>
+                    </q-btn>
+                    <q-btn round flat push color="red" icon="close" @click="editDataCancel()">
+                      <q-tooltip content-class="bg-amber text-black shadow-4" :offset="[10, 10]"
+                        content-style="font-size: 12px">
+                        {{ $t('canceledit') }}
+                      </q-tooltip>
+                    </q-btn>
+                  </q-td>
+                </template>
+                <template v-else-if="props.row.id !== editid"></template>
+              </template>
+            </q-tr>
+          </template>
+        </q-table>
+      </transition>
+      <template>
+        <div v-show="max !== 0" class="q-pa-lg flex flex-center">
+          <div>{{ total }} </div>
+          <q-pagination v-model="current" color="black" :max="max" :max-pages="6" boundary-links @click="getList()" />
+          <div>
+            <input v-model="paginationIpt" @blur="changePageEnter" @keyup.enter="changePageEnter"
+              style="width: 60px; text-align: center" />
+          </div>
+        </div>
+        <div v-show="max === 0" class="q-pa-lg flex flex-center">
+          <q-btn flat push color="dark" :label="$t('no_data')"></q-btn>
+        </div>
+      </template>
+      <q-dialog v-model="newForm">
+        <q-card class="shadow-24">
+          <q-bar class="bg-light-blue-10 text-white rounded-borders" style="height: 50px">
+            <div>{{ $t('newtip') }}</div>
+            <q-space />
+            <q-btn dense flat icon="close" v-close-popup>
+              <q-tooltip content-class="bg-amber text-black shadow-4">{{ $t('index.close') }}</q-tooltip>
+            </q-btn>
+          </q-bar>
+          <q-card-section style="max-height: 325px; width: 400px" class="scroll">
+            <q-input dense outlined square v-model="newFormData.product_std"
+              :label="'产品标准'" autofocus
+              :rules="[val => val && val.length > 0 || error1]"  />
+            <q-input dense outlined square v-model="newFormData.product_code"
+              :label="'产品代码'" autofocus
+              :rules="[val => val && val.length > 0 || error0]"  />
+            <q-input dense outlined square v-model="newFormData.product_name"
+              :label="'产品名称'" :rules="[val => val && val.length > 0 || error1]"
+              @keyup.enter="newDataSubmit()" />
+            
+
+  
+          </q-card-section>
+          <div style="float: right; padding: 15px 15px 15px 0">
+            <q-btn color="white" text-color="black" style="margin-right: 25px" @click="newDataCancel()">{{ $t('cancel')
+              }}</q-btn>
+            <q-btn color="primary" @click="newDataSubmit()">{{ $t('submit') }}</q-btn>
+          </div>
+        </q-card>
+      </q-dialog>
+      <q-dialog v-model="deleteForm">
+        <q-card class="shadow-24">
+          <q-bar class="bg-light-blue-10 text-white rounded-borders" style="height: 50px">
+            <div>{{ $t('delete') }}</div>
+            <q-space />
+            <q-btn dense flat icon="close" v-close-popup>
+              <q-tooltip content-class="bg-amber text-black shadow-4">{{ $t('index.close') }}</q-tooltip>
+            </q-btn>
+          </q-bar>
+          <q-card-section style="max-height: 325px; width: 400px" class="scroll">
+            {{ $t('deletetip') }}
+          </q-card-section>
+          <div style="float: right; padding: 15px 15px 15px 0">
+            <q-btn color="white" text-color="black" style="margin-right: 25px" @click="deleteDataCancel()">{{ $t('cancel')
+              }}</q-btn>
+            <q-btn color="primary" @click="deleteDataSubmit()">{{ $t('submit') }}</q-btn>
+          </div>
+        </q-card>
+      </q-dialog>
+
+    </div>
+  </template>
+  <router-view />
+  
+  <script>
+  import { getauth, postauth, putauth, deleteauth } from 'boot/axios_request'
+  import { LocalStorage } from 'quasar'
+  import axios from 'axios'
+  
+  export default {
+    name: 'Pageproduct',
+    data() {
+      return {
+        openid: '',
+        login_name: '',
+        authin: '0',
+        pathname: 'warehouse/product/',
+        pathname_previous: '',
+        pathname_next: '',
+        separator: 'cell',
+        loading: false,
+        height: '',
+        table_list: [],
+        columns: [
+            { name: 'product_std', required: true, label: '产品标准', align: 'left', field: 'product_std' ,sortable: true},
+          { name: 'product_code', required: true, label: '产品代码', align: 'left', field: 'product_code' ,sortable: true},
+          { name: 'product_name', required: true, label: '产品名称', align: 'left', field: 'product_name' ,sortable: true},
+          { name: 'creater', label: this.$t('creater'), field: 'creater', align: 'center' },
+
+          { name: 'action', label: this.$t('action'), align: 'center' }
+        ],
+        filter: '',
+        pagination: {
+          page: 1,
+          rowsPerPage: '30'
+        },
+        newForm: false,
+        newFormData: {
+                product_std: '',
+                product_code: '',
+                product_name: '',
+                creater: ''
+        },
+        editid: 0,
+        editFormData: {},
+        editMode: false,
+        deleteForm: false,
+        deleteid: 0,
+        publishForm: false,
+        publishdetail: '',
+        square_measure: '',
+        error0: this.$t('warehouse.view_warehouseset.error0'),
+        
+        error1: this.$t('warehouse.view_warehouseset.error1'),
+        error2: this.$t('warehouse.view_warehouseset.error2'),
+        error3: this.$t('warehouse.view_warehouseset.error3'),
+        error4: this.$t('warehouse.view_warehouseset.error4'),
+        error5: this.$t('warehouse.view_warehouseset.error5'),
+        current: 1,
+        max: 0,
+        total: 0,
+        paginationIpt: 1
+      }
+    },
+    methods: {
+      getList() {
+        var _this = this
+        if (LocalStorage.has('auth')) {
+          getauth(_this.pathname + '?page=' + '' + _this.current, {
+          }).then(res => {
+            _this.table_list = res.results
+            _this.total = res.count
+            if (res.count === 0) {
+              _this.max = 0
+            } else {
+              if (Math.ceil(res.count / 30) === 1) {
+                _this.max = 0
+              } else {
+                _this.max = Math.ceil(res.count / 30)
+              }
+            }
+            _this.pathname_previous = res.previous
+            _this.pathname_next = res.next
+          }).catch(err => {
+            _this.$q.notify({
+              message: err.detail,
+              icon: 'close',
+              color: 'negative'
+            })
+          })
+        }
+      },
+      changePageEnter(e) {
+        if (Number(this.paginationIpt) < 1) {
+          this.current = 1
+          this.paginationIpt = 1
+        } else if (Number(this.paginationIpt) > this.max) {
+          this.current = this.max
+          this.paginationIpt = this.max
+        } else {
+          this.current = Number(this.paginationIpt)
+        }
+        this.getList()
+      },
+      getListPrevious() {
+        var _this = this
+        if (LocalStorage.has('auth')) {
+          getauth(_this.pathname_previous, {
+          }).then(res => {
+            _this.table_list = res.results
+            _this.pathname_previous = res.previous
+            _this.pathname_next = res.next
+          }).catch(err => {
+            _this.$q.notify({
+              message: err.detail,
+              icon: 'close',
+              color: 'negative'
+            })
+          })
+        }
+      },
+      getListNext() {
+        var _this = this
+        if (LocalStorage.has('auth')) {
+          getauth(_this.pathname_next, {
+          }).then(res => {
+            _this.table_list = res.results
+            _this.pathname_previous = res.previous
+            _this.pathname_next = res.next
+          }).catch(err => {
+            _this.$q.notify({
+              message: err.detail,
+              icon: 'close',
+              color: 'negative'
+            })
+          })
+        } else {
+        }
+      },
+      reFresh() {
+        var _this = this
+        _this.getList()
+      },
+      newFormCheck() {
+        var _this = this
+
+          _this.newForm = true
+
+      },
+      newDataSubmit() {
+        var _this = this
+        var productsets = []
+        _this.table_list.forEach(i => {
+          productsets.push(i.product_name)
+        })
+        if (productsets.indexOf(_this.newFormData.product_name) === -1 && _this.newFormData.product_name.length !== 0) {
+          _this.newFormData.creater = _this.login_name
+          postauth(_this.pathname, _this.newFormData).then(res => {
+            _this.getList()
+            _this.newDataCancel()
+            _this.$q.notify({
+              message: 'Success Create',
+              icon: 'check',
+              color: 'green'
+            })
+          }).catch(err => {
+            _this.$q.notify({
+              message: err.detail,
+              icon: 'close',
+              color: 'negative'
+            })
+          })
+        } else {
+          _this.newFormData.creater = _this.login_name
+          postauth(_this.pathname, _this.newFormData).then(res => {
+            _this.getList()
+            _this.newDataCancel()
+            _this.$q.notify({
+              message: '',
+              icon: 'close',
+              color: 'negative'
+            })
+          }).catch(err => {
+            _this.$q.notify({
+              message: err.detail,
+              icon: 'close',
+              color: 'negative'
+            })
+          })
+        }
+        productsets = []
+      },
+      newDataCancel() {
+        var _this = this
+        _this.newForm = false
+        _this.newFormData = {
+                product_std: '',
+                product_code: '',
+                product_name: '',
+                creater: ''
+        }
+      },
+      editData(e) {
+        var _this = this
+        _this.editMode = true
+        _this.editid = e.id
+        _this.editFormData = {
+                product_std: e.product_std,
+                product_code: e.product_code,
+                product_name: e.product_name,
+                creater: _this.login_name
+        }
+      },
+      editDataSubmit() {
+        var _this = this
+        putauth(_this.pathname + _this.editid + '/', _this.editFormData).then(res => {
+          _this.editDataCancel()
+          _this.getList()
+          _this.$q.notify({
+            message: 'Success Edit Data',
+            icon: 'check',
+            color: 'green'
+          })
+        }).catch(err => {
+          _this.$q.notify({
+            message: err.detail,
+            icon: 'close',
+            color: 'negative'
+          })
+        })
+      },
+      editDataCancel() {
+        var _this = this
+        _this.editMode = false
+        _this.editid = 0
+        _this.editFormData = {
+                product_std: '',
+                product_code: '',
+                product_name: '',
+                creater: ''
+        }
+      },
+      deleteData(e) {
+        var _this = this
+        _this.deleteForm = true
+        _this.deleteid = e
+      },
+      deleteDataSubmit() {
+        var _this = this
+        deleteauth(_this.pathname + _this.deleteid + '/').then(res => {
+          _this.deleteDataCancel()
+          _this.getList()
+          _this.$q.notify({
+            message: 'Success Edit Data',
+            icon: 'check',
+            color: 'green'
+          })
+        }).catch(err => {
+          _this.$q.notify({
+            message: err.detail,
+            icon: 'close',
+            color: 'negative'
+          })
+        })
+      },
+      deleteDataCancel() {
+        var _this = this
+        _this.deleteForm = false
+        _this.deleteid = 0
+      }
+      
+    
+    },
+    created() {
+      var _this = this
+      if (LocalStorage.has('openid')) {
+        _this.openid = LocalStorage.getItem('openid')
+      } else {
+        _this.openid = ''
+        LocalStorage.set('openid', '')
+      }
+      if (LocalStorage.has('login_name')) {
+        _this.login_name = LocalStorage.getItem('login_name')
+      } else {
+        _this.login_name = ''
+        LocalStorage.set('login_name', '')
+      }
+      if (LocalStorage.has('auth')) {
+        _this.authin = '1'
+        _this.getList()
+      } else {
+        _this.authin = '0'
+      }
+    },
+    mounted() {
+      var _this = this
+      if (_this.$q.platform.is.electron) {
+        _this.height = String(_this.$q.screen.height - 290) + 'px'
+      } else {
+        _this.height = _this.$q.screen.height - 290 + '' + 'px'
+      }
+    },
+    updated() {
+    },
+    destroyed() {
+    }
+  }
+  </script>
+  

+ 3 - 1
templates/src/pages/warehouse/warehouse.vue

@@ -21,7 +21,9 @@
         <transition appear enter-active-class="animated zoomIn">
           <q-route-tab name="bound_type" :label="$t('warehouse.bdtype')" icon="exposure" :to="{ name: 'boundtype' }" exact/>
         </transition>
-       
+        <transition appear enter-active-class="animated zoomIn">
+          <q-route-tab name="product" :label="'产品编码'" icon="exposure" :to="{ name: 'product' }" exact/>
+        </transition>
 
 
 

+ 6 - 0
templates/src/router/routes.js

@@ -272,6 +272,12 @@ const routes = [{
         name: 'status',
         component: () => import('pages/warehouse/boundstatus.vue')
       },
+      {
+        path:'product',
+        name:'product',
+        component: () => import('pages/warehouse/product.vue')
+      }
+      
       ]
     },
     {

binární
warehouse/__pycache__/admin.cpython-38.pyc


binární
warehouse/__pycache__/filter.cpython-38.pyc


binární
warehouse/__pycache__/models.cpython-38.pyc


binární
warehouse/__pycache__/serializers.cpython-38.pyc


binární
warehouse/__pycache__/urls.cpython-38.pyc


binární
warehouse/__pycache__/views.cpython-38.pyc


+ 2 - 1
warehouse/admin.py

@@ -1,6 +1,6 @@
 from django.contrib import admin
 
-from .models import ListModel,DepartmentListModel,BoundTypeListModel,BoundBSListModel,BoundCodeTypeListModel
+from .models import ListModel,DepartmentListModel,BoundTypeListModel,BoundBSListModel,BoundCodeTypeListModel,ProductListModel
 
 
 admin.site.register(ListModel)
@@ -8,3 +8,4 @@ admin.site.register(DepartmentListModel)
 admin.site.register(BoundTypeListModel)
 admin.site.register(BoundBSListModel)
 admin.site.register(BoundCodeTypeListModel)
+admin.site.register(ProductListModel)

+ 15 - 2
warehouse/filter.py

@@ -1,5 +1,5 @@
 from django_filters import FilterSet
-from .models import ListModel,DepartmentListModel,BoundTypeListModel,BoundBSListModel,BoundCodeTypeListModel,BoundStatusListModel
+from .models import ListModel,DepartmentListModel,BoundTypeListModel,BoundBSListModel,BoundCodeTypeListModel,BoundStatusListModel,ProductListModel
 
 class Filter(FilterSet):
     class Meta:
@@ -86,4 +86,17 @@ class BoundStatusFilter(FilterSet):
             "create_time": ['year', 'month', 'day', 'week_day', 'gt', 'gte', 'lt', 'lte', 'range'],
             "update_time": ['year', 'month', 'day', 'week_day', 'gt', 'gte', 'lt', 'lte', 'range']
         }
-            
+            
+class ProductFilter(FilterSet):
+    class Meta:
+        model = ProductListModel
+        fields = {
+            "id": ['exact', 'gt', 'gte', 'lt', 'lte', 'isnull', 'in', 'range'],
+            "product_name": ['exact', 'iexact', 'contains', 'icontains'],
+            "product_code": ['exact', 'iexact', 'contains', 'icontains'],
+            "product_std": ['exact', 'iexact', 'contains', 'icontains'],
+            "creater": ['exact', 'iexact', 'contains', 'icontains'],
+            "is_delete": ['exact', 'iexact']
+        }
+
+        

+ 115 - 1
warehouse/migrations/0001_initial.py

@@ -1,4 +1,4 @@
-# Generated by Django 4.1.2 on 2025-03-15 17:44
+# Generated by Django 4.1.2 on 2025-03-28 10:18
 
 from django.db import migrations, models
 
@@ -11,6 +11,103 @@ class Migration(migrations.Migration):
     ]
 
     operations = [
+        migrations.CreateModel(
+            name='BoundBSListModel',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('bound_bs_code', models.CharField(max_length=255, verbose_name='Bound Business Code')),
+                ('bound_bs_name', models.CharField(max_length=255, verbose_name='Bound  Business Name')),
+                ('creater', models.CharField(max_length=255, verbose_name='Who Created')),
+                ('openid', models.CharField(max_length=255, verbose_name='Openid')),
+                ('is_delete', models.BooleanField(default=False, verbose_name='Delete Label')),
+                ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='Create Time')),
+                ('update_time', models.DateTimeField(auto_now=True, null=True, verbose_name='Update Time')),
+            ],
+            options={
+                'verbose_name': 'Bound Business',
+                'verbose_name_plural': 'Bound Business',
+                'db_table': 'bound_business',
+                'ordering': ['-id'],
+            },
+        ),
+        migrations.CreateModel(
+            name='BoundCodeTypeListModel',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('bound_code_type_code', models.CharField(max_length=255, verbose_name='Bound Code Type Code')),
+                ('bound_code_type_name', models.CharField(max_length=255, verbose_name='Bound Code Type Name')),
+                ('creater', models.CharField(max_length=255, verbose_name='Who Created')),
+                ('openid', models.CharField(max_length=255, verbose_name='Openid')),
+                ('is_delete', models.BooleanField(default=False, verbose_name='Delete Label')),
+                ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='Create Time')),
+                ('update_time', models.DateTimeField(auto_now=True, null=True, verbose_name='Update Time')),
+            ],
+            options={
+                'verbose_name': 'Bound Code Type',
+                'verbose_name_plural': 'Bound Code Type',
+                'db_table': 'bound_code_type',
+                'ordering': ['-id'],
+            },
+        ),
+        migrations.CreateModel(
+            name='BoundStatusListModel',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('bound_status_code', models.IntegerField(default=0, verbose_name='Bound Status Code')),
+                ('bound_status_name', models.CharField(max_length=255, verbose_name='Bound Status Name')),
+                ('creater', models.CharField(max_length=255, verbose_name='Who Created')),
+                ('openid', models.CharField(max_length=255, verbose_name='Openid')),
+                ('is_delete', models.BooleanField(default=False, verbose_name='Delete Label')),
+                ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='Create Time')),
+                ('update_time', models.DateTimeField(auto_now=True, null=True, verbose_name='Update Time')),
+            ],
+            options={
+                'verbose_name': 'Bound Status',
+                'verbose_name_plural': 'Bound Status',
+                'db_table': 'bound_status',
+                'ordering': ['-id'],
+            },
+        ),
+        migrations.CreateModel(
+            name='BoundTypeListModel',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('bound_type_code', models.CharField(max_length=255, verbose_name='Bound Type Code')),
+                ('bound_type_name', models.CharField(max_length=255, verbose_name='Bound Type Name')),
+                ('creater', models.CharField(max_length=255, verbose_name='Who Created')),
+                ('openid', models.CharField(max_length=255, verbose_name='Openid')),
+                ('is_delete', models.BooleanField(default=False, verbose_name='Delete Label')),
+                ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='Create Time')),
+                ('update_time', models.DateTimeField(auto_now=True, null=True, verbose_name='Update Time')),
+            ],
+            options={
+                'verbose_name': 'Bound Type',
+                'verbose_name_plural': 'Bound Type',
+                'db_table': 'bound_type',
+                'ordering': ['-id'],
+            },
+        ),
+        migrations.CreateModel(
+            name='DepartmentListModel',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('department_code', models.CharField(max_length=255, verbose_name='Department Code')),
+                ('department_name', models.CharField(max_length=255, verbose_name='Department Name')),
+                ('department_contact', models.CharField(max_length=255, verbose_name='Department Contact')),
+                ('department_manager', models.CharField(max_length=255, verbose_name='Department Manager')),
+                ('creater', models.CharField(max_length=255, verbose_name='Who Created')),
+                ('openid', models.CharField(max_length=255, verbose_name='Openid')),
+                ('is_delete', models.BooleanField(default=False, verbose_name='Delete Label')),
+                ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='Create Time')),
+                ('update_time', models.DateTimeField(auto_now=True, null=True, verbose_name='Update Time')),
+            ],
+            options={
+                'verbose_name': 'Department',
+                'verbose_name_plural': 'Department',
+                'db_table': 'department',
+                'ordering': ['-id'],
+            },
+        ),
         migrations.CreateModel(
             name='ListModel',
             fields=[
@@ -34,4 +131,21 @@ class Migration(migrations.Migration):
                 'ordering': ['-id'],
             },
         ),
+        migrations.CreateModel(
+            name='ProductListModel',
+            fields=[
+                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('product_code', models.CharField(max_length=255, verbose_name='Product Code')),
+                ('product_name', models.CharField(max_length=255, verbose_name='Product Name')),
+                ('product_std', models.CharField(max_length=255, verbose_name='Product Description')),
+                ('creater', models.CharField(default='first', max_length=255, verbose_name='Who Created')),
+                ('is_delete', models.BooleanField(default=False, verbose_name='Delete Label')),
+            ],
+            options={
+                'verbose_name': 'Product',
+                'verbose_name_plural': 'Product',
+                'db_table': 'product',
+                'ordering': ['-id'],
+            },
+        ),
     ]

+ 0 - 91
warehouse/migrations/0002_boundbslistmodel_boundcodetypelistmodel_and_more.py

@@ -1,91 +0,0 @@
-# Generated by Django 4.1.2 on 2025-03-26 12:45
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('warehouse', '0001_initial'),
-    ]
-
-    operations = [
-        migrations.CreateModel(
-            name='BoundBSListModel',
-            fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('bound_bs_code', models.CharField(max_length=255, verbose_name='Bound Business Code')),
-                ('bound_bs_name', models.CharField(max_length=255, verbose_name='Bound  Business Name')),
-                ('creater', models.CharField(max_length=255, verbose_name='Who Created')),
-                ('openid', models.CharField(max_length=255, verbose_name='Openid')),
-                ('is_delete', models.BooleanField(default=False, verbose_name='Delete Label')),
-                ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='Create Time')),
-                ('update_time', models.DateTimeField(auto_now=True, null=True, verbose_name='Update Time')),
-            ],
-            options={
-                'verbose_name': 'Bound Business',
-                'verbose_name_plural': 'Bound Business',
-                'db_table': 'bound_business',
-                'ordering': ['-id'],
-            },
-        ),
-        migrations.CreateModel(
-            name='BoundCodeTypeListModel',
-            fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('bound_code_type_code', models.CharField(max_length=255, verbose_name='Bound Code Type Code')),
-                ('bound_code_type_name', models.CharField(max_length=255, verbose_name='Bound Code Type Name')),
-                ('creater', models.CharField(max_length=255, verbose_name='Who Created')),
-                ('openid', models.CharField(max_length=255, verbose_name='Openid')),
-                ('is_delete', models.BooleanField(default=False, verbose_name='Delete Label')),
-                ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='Create Time')),
-                ('update_time', models.DateTimeField(auto_now=True, null=True, verbose_name='Update Time')),
-            ],
-            options={
-                'verbose_name': 'Bound Code Type',
-                'verbose_name_plural': 'Bound Code Type',
-                'db_table': 'bound_code_type',
-                'ordering': ['-id'],
-            },
-        ),
-        migrations.CreateModel(
-            name='BoundTypeListModel',
-            fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('bound_type_code', models.CharField(max_length=255, verbose_name='Bound Type Code')),
-                ('bound_type_name', models.CharField(max_length=255, verbose_name='Bound Type Name')),
-                ('creater', models.CharField(max_length=255, verbose_name='Who Created')),
-                ('openid', models.CharField(max_length=255, verbose_name='Openid')),
-                ('is_delete', models.BooleanField(default=False, verbose_name='Delete Label')),
-                ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='Create Time')),
-                ('update_time', models.DateTimeField(auto_now=True, null=True, verbose_name='Update Time')),
-            ],
-            options={
-                'verbose_name': 'Bound Type',
-                'verbose_name_plural': 'Bound Type',
-                'db_table': 'bound_type',
-                'ordering': ['-id'],
-            },
-        ),
-        migrations.CreateModel(
-            name='DepartmentListModel',
-            fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('department_code', models.CharField(max_length=255, verbose_name='Department Code')),
-                ('department_name', models.CharField(max_length=255, verbose_name='Department Name')),
-                ('department_contact', models.CharField(max_length=255, verbose_name='Department Contact')),
-                ('department_manager', models.CharField(max_length=255, verbose_name='Department Manager')),
-                ('creater', models.CharField(max_length=255, verbose_name='Who Created')),
-                ('openid', models.CharField(max_length=255, verbose_name='Openid')),
-                ('is_delete', models.BooleanField(default=False, verbose_name='Delete Label')),
-                ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='Create Time')),
-                ('update_time', models.DateTimeField(auto_now=True, null=True, verbose_name='Update Time')),
-            ],
-            options={
-                'verbose_name': 'Department',
-                'verbose_name_plural': 'Department',
-                'db_table': 'department',
-                'ordering': ['-id'],
-            },
-        ),
-    ]

+ 0 - 32
warehouse/migrations/0003_boundstatuslistmodel.py

@@ -1,32 +0,0 @@
-# Generated by Django 4.1.2 on 2025-03-27 11:19
-
-from django.db import migrations, models
-
-
-class Migration(migrations.Migration):
-
-    dependencies = [
-        ('warehouse', '0002_boundbslistmodel_boundcodetypelistmodel_and_more'),
-    ]
-
-    operations = [
-        migrations.CreateModel(
-            name='BoundStatusListModel',
-            fields=[
-                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
-                ('bound_status_code', models.IntegerField(default=0, verbose_name='Bound Status Code')),
-                ('bound_status_name', models.CharField(max_length=255, verbose_name='Bound Status Name')),
-                ('creater', models.CharField(max_length=255, verbose_name='Who Created')),
-                ('openid', models.CharField(max_length=255, verbose_name='Openid')),
-                ('is_delete', models.BooleanField(default=False, verbose_name='Delete Label')),
-                ('create_time', models.DateTimeField(auto_now_add=True, verbose_name='Create Time')),
-                ('update_time', models.DateTimeField(auto_now=True, null=True, verbose_name='Update Time')),
-            ],
-            options={
-                'verbose_name': 'Bound Status',
-                'verbose_name_plural': 'Bound Status',
-                'db_table': 'bound_status',
-                'ordering': ['-id'],
-            },
-        ),
-    ]

binární
warehouse/migrations/__pycache__/0001_initial.cpython-38.pyc


binární
warehouse/migrations/__pycache__/0002_boundbslistmodel_boundcodetypelistmodel_and_more.cpython-38.pyc


binární
warehouse/migrations/__pycache__/0003_boundstatuslistmodel.cpython-38.pyc


binární
warehouse/migrations/__pycache__/0004_productlistmodel.cpython-38.pyc


binární
warehouse/migrations/__pycache__/0005_alter_productlistmodel_product_code.cpython-38.pyc


binární
warehouse/migrations/__pycache__/0006_alter_productlistmodel_product_code.cpython-38.pyc


binární
warehouse/migrations/__pycache__/0007_remove_productlistmodel_create_time_and_more.cpython-38.pyc


+ 16 - 1
warehouse/models.py

@@ -99,4 +99,19 @@ class BoundStatusListModel(models.Model):
         db_table = 'bound_status'
         verbose_name = 'Bound Status'
         verbose_name_plural = "Bound Status"  
-        ordering = ['-id']
+        ordering = ['-id']
+
+class ProductListModel(models.Model):
+    product_code = models.CharField(max_length=255, verbose_name="Product Code"  )
+    product_name = models.CharField(max_length=255, verbose_name="Product Name")
+    product_std = models.CharField(max_length=255, verbose_name="Product Description")
+
+    creater = models.CharField(default='first', max_length=255, verbose_name="Who Created")
+    is_delete = models.BooleanField(default=False, verbose_name='Delete Label')
+
+
+    class Meta: 
+        db_table = 'product'
+        verbose_name = 'Product'
+        verbose_name_plural = "Product"  
+        ordering = ['-id']

+ 55 - 1
warehouse/serializers.py

@@ -1,5 +1,5 @@
 from rest_framework import serializers
-from .models import ListModel,DepartmentListModel,BoundTypeListModel,BoundBSListModel,BoundCodeTypeListModel,BoundStatusListModel
+from .models import ListModel,DepartmentListModel,BoundTypeListModel,BoundBSListModel,BoundCodeTypeListModel,BoundStatusListModel,ProductListModel
 from utils import datasolve
 
 
@@ -305,3 +305,57 @@ class BoundStatusPartialUpdateSerializer(serializers.ModelSerializer):
         exclude = ['openid', 'is_delete', ]
         read_only_fields = ['id', 'create_time', 'update_time', ]
 
+class ProductGetSerializer(serializers.ModelSerializer):
+    product_name = serializers.CharField(read_only=True, required=False)
+    product_code = serializers.CharField(read_only=True, required=False)
+    product_std = serializers.CharField(read_only=True, required=False)
+    creater = serializers.CharField(read_only=True, required=False)    
+ 
+
+    class Meta:
+        model = ProductListModel
+        exclude = ['is_delete', ]
+        read_only_fields = ['id', ]
+
+class ProductPostSerializer(serializers.ModelSerializer):
+
+    product_name = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate],
+                                           max_length=45, min_length=1)
+    product_code = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate],
+                                           max_length=45, min_length=1)
+    product_std = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate],
+                                           max_length=45, min_length=1)
+    creater = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
+
+    class Meta:
+        model = ProductListModel
+        exclude = ['is_delete', ]
+        read_only_fields = ['id',  ]
+
+class ProductUpdateSerializer(serializers.ModelSerializer):
+    product_name = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate],
+                                           max_length=45, min_length=1)
+    product_code = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate],
+                                           max_length=45, min_length=1)
+    product_std = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate],
+                                           max_length=45, min_length=1)
+    creater = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
+
+    class Meta:
+        model = ProductListModel
+        exclude = [ 'is_delete', ]
+        read_only_fields = ['id',]
+
+class ProductPartialUpdateSerializer(serializers.ModelSerializer):
+    product_name = serializers.CharField(read_only=False, required=True, validators=[datasolve.data_validate],
+                                           max_length=45, min_length=1)
+    product_code = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate],
+                                           max_length=45, min_length=1)
+    product_std = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate],
+                                           max_length=45, min_length=1)
+    creater = serializers.CharField(read_only=False, required=False, validators=[datasolve.data_validate])
+
+    class Meta:
+        model = ProductListModel
+        exclude = ['is_delete', ]
+        read_only_fields = ['id',  ]

+ 9 - 0
warehouse/urls.py

@@ -56,6 +56,15 @@ urlpatterns = [
     }), name="status_1"),
         # 批量操作基础端点:批量查询接口
     path(r'multiple/', views.MultipleViewSet.as_view({"get": "list"}), name="warehouse"),
+
+    path(r'product/', views.ProductAPIViewSet.as_view({"get": "list", "post": "create"}), name="product"),
+    re_path(r'product/(?P<pk>\d+)/$', views.ProductAPIViewSet.as_view({
+        'get': 'retrieve',
+        'put': 'update',
+        'patch': 'partial_update',
+        'delete': 'destroy'
+    }), name="product_1"),  
+  
     
 
 ]

+ 97 - 2
warehouse/views.py

@@ -1,12 +1,12 @@
 from rest_framework import viewsets
-from .models import ListModel,DepartmentListModel,BoundTypeListModel,BoundBSListModel,BoundCodeTypeListModel,BoundStatusListModel
+from .models import ListModel,DepartmentListModel,BoundTypeListModel,BoundBSListModel,BoundCodeTypeListModel,BoundStatusListModel,ProductListModel
 
 from . import serializers
 from utils.page import MyPageNumberPagination
 from rest_framework.filters import OrderingFilter
 from django_filters.rest_framework import DjangoFilterBackend
 from rest_framework.response import Response
-from .filter import Filter,DepartmentFilter,BoundTypeFilter,BoundBSFilter,BoundCodeTypeFilter,BoundStatusFilter
+from .filter import Filter,DepartmentFilter,BoundTypeFilter,BoundBSFilter,BoundCodeTypeFilter,BoundStatusFilter,ProductFilter
 from rest_framework.exceptions import APIException
 
 
@@ -671,3 +671,98 @@ class MultipleViewSet(viewsets.ModelViewSet):
         else:
             return self.http_method_not_allowed(request=self.request)            
             
+class ProductAPIViewSet(viewsets.ModelViewSet):
+    pagination_class = MyPageNumberPagination
+    filter_backends = [DjangoFilterBackend, OrderingFilter, ]
+    ordering_fields = ['id', "create_time", "update_time", ]
+    filter_class = ProductFilter
+
+    def get_project(self):
+        # 获取项目ID,如果不存在则返回None
+        try:
+            id = self.kwargs.get('pk')
+            return id
+        except:
+            return None
+
+    def get_queryset(self):
+        # 根据请求用户过滤查询集
+        id = self.get_project()
+        if self.request.user:
+            if id is None:
+                return ProductListModel.objects.filter(is_delete=False)
+            else:
+                return ProductListModel.objects.filter(id=id, is_delete=False)
+        else:
+            return ProductListModel.objects.none()
+
+    def get_serializer_class(self):
+        # 根据操作类型选择合适的序列化器
+        if self.action in ['list', 'retrieve', 'destroy']:
+            return serializers.ProductGetSerializer
+        elif self.action in ['create']:
+            return serializers.ProductPostSerializer
+        elif self.action in ['update']:
+            return serializers.ProductUpdateSerializer
+        elif self.action in ['partial_update']:
+            return serializers.ProductPartialUpdateSerializer
+        else:
+            return self.http_method_not_allowed(request=self.request)
+
+    def create(self, request, *args, **kwargs):
+        # 创建一个数据行
+        data = self.request.data
+
+        if len(data['product_name']) > 45:
+            raise APIException({"detail": "The product name is set to more than 45 characters"})
+        if ProductListModel.objects.filter(product_code=data['product_code'],
+                                             is_delete=False).exists():
+            raise APIException({"detail": "Data Exists"})
+        else:
+            serializer = self.get_serializer(data=data)
+            serializer.is_valid(raise_exception=True)
+            serializer.save()
+            headers = self.get_success_headers(serializer.data)
+            return Response(serializer.data, status=200, headers=headers)
+    
+    def update(self, request, pk):
+        # 更新一个数据行
+        qs = self.get_object()
+       
+        data = self.request.data
+        if len(data['product_name']) > 45:
+            raise APIException({"detail": "The product name is set to more than 45 characters"})
+        if ProductListModel.objects.filter(product_code=data['product_code'],
+                                            is_delete=False).exists():
+            raise APIException({"detail": "Data Exists"})
+        serializer = self.get_serializer(qs, data=data)
+        serializer.is_valid(raise_exception=True)
+        serializer.save()
+        headers = self.get_success_headers(serializer.data)
+        return Response(serializer.data, status=200, headers=headers)
+
+    def partial_update(self, request, pk):
+        # 部分更新一个数据行
+        qs = self.get_object()
+       
+        data = self.request.data
+        if len(data['product_name']) > 45:
+            raise APIException({"detail": "The product name is set to more than 45 characters"})
+        if ProductListModel.objects.filter(product_code=data['product_code'],
+                                            is_delete=False).exists():
+            raise APIException({"detail": "Data Exists"})
+        serializer = self.get_serializer(qs, data=data, partial=True)
+        serializer.is_valid(raise_exception=True)
+        serializer.save()
+        headers = self.get_success_headers(serializer.data)
+        return Response(serializer.data, status=200, headers=headers)
+
+    def destroy(self, request, pk):
+        # 逻辑删除一个数据行
+        qs = self.get_object()
+
+        qs.is_delete = True
+        qs.save()
+        serializer = self.get_serializer(qs, many=False)
+        headers = self.get_success_headers(serializer.data)
+        return Response(serializer.data, status=200, headers=headers)