diff --git a/hb_client/package.json b/hb_client/package.json index 1382831..0a17f55 100644 --- a/hb_client/package.json +++ b/hb_client/package.json @@ -31,6 +31,7 @@ "path-to-regexp": "^6.2.0", "vue": "^2.6.14", "vue-json-editor": "^1.4.3", + "vue-quill-editor": "^3.0.6", "vue-router": "^3.5.2", "vuex": "^3.6.2", "webpack-dev-server": "^4.2.0", diff --git a/hb_client/src/router/index.js b/hb_client/src/router/index.js index 87508ea..9685b0e 100644 --- a/hb_client/src/router/index.js +++ b/hb_client/src/router/index.js @@ -176,6 +176,13 @@ export const asyncRoutes = [ meta: { title: '合同信息', icon: 'example', perms: ['index_manage'] } } , + { + path: 'review', + name: 'review', + component: () => import('@/views/sam/review'), + meta: { title: '合同评审', icon: 'example', perms: ['index_manage'] } + } + , { path: 'order', name: 'order', diff --git a/hb_client/src/views/mtm/productprocess.vue b/hb_client/src/views/mtm/productprocess.vue index e810968..29afc03 100644 --- a/hb_client/src/views/mtm/productprocess.vue +++ b/hb_client/src/views/mtm/productprocess.vue @@ -386,12 +386,15 @@ > - + - - - + + + + + + { + getMaterialList({pageoff:true}).then((response) => { if (response.data) { - this.materialoptions = genTree(response.data.results); + this.materialoptions = genTree(response.data); } this.listLoading = false; }); @@ -546,6 +553,7 @@ export default { { this.process = id; // alert(this.process) + this.getmaterialList();//物料列表 this.getInputmaterialLists();//输入物料 this.getOutputmaterialLists();//输出物料 @@ -564,7 +572,6 @@ export default { this.listQueryinput.process=this.process; this.listQueryinput.product=this.product - //this.listQueryinput.page=0; getInputmaterialList(this.listQueryinput).then((response) => { if (response.data) { diff --git a/hb_client/src/views/mtm/step.vue b/hb_client/src/views/mtm/step.vue index d614d5d..48f3c4d 100644 --- a/hb_client/src/views/mtm/step.vue +++ b/hb_client/src/views/mtm/step.vue @@ -6,7 +6,7 @@ font-weight: 700; ">子工序列表 - 新增子工序 过程记录表 - 新增 - + + + + + @@ -112,7 +116,9 @@ - + + + + + + @@ -117,6 +120,7 @@ + diff --git a/hb_client/src/views/sam/review.vue b/hb_client/src/views/sam/review.vue new file mode 100644 index 0000000..abd14b4 --- /dev/null +++ b/hb_client/src/views/sam/review.vue @@ -0,0 +1,284 @@ + + diff --git a/hb_daq/.gitignore b/hb_daq/.gitignore new file mode 100644 index 0000000..1f2de66 --- /dev/null +++ b/hb_daq/.gitignore @@ -0,0 +1,3 @@ +dist/ +config/* +.build/ \ No newline at end of file diff --git a/hb_daq/default.aproj b/hb_daq/default.aproj new file mode 100644 index 0000000..c3e936d --- /dev/null +++ b/hb_daq/default.aproj @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/hb_daq/dlg/add.aardio b/hb_daq/dlg/add.aardio new file mode 100644 index 0000000..463f520 --- /dev/null +++ b/hb_daq/dlg/add.aardio @@ -0,0 +1,24 @@ +import win.ui; +/*DSG{{*/ +var winform = win.form(text="新建采集内容";right=299;bottom=179;border="dialog frame";max=false;min=false) +winform.add( +button={cls="button";text="确定";left=90;top=119;right=196;bottom=154;z=5}; +edit={cls="edit";left=84;top=26;right=281;bottom=50;dl=1;dr=1;dt=1;edge=1;z=2}; +edit2={cls="edit";left=84;top=69;right=281;bottom=93;dl=1;dr=1;dt=1;edge=1;z=4}; +static={cls="static";text="设备编号";left=8;top=29;right=78;bottom=54;dl=1;dt=1;notify=1;transparent=1;z=1}; +static2={cls="static";text="文件夹地址";left=8;top=74;right=78;bottom=99;dl=1;dt=1;notify=1;transparent=1;z=3} +) +/*}}*/ + +winform.button.oncommand = function(id,event){ + if(winform.edit.text!="" && winform.edit2.text!=""){ + winform.parent.listview.addItem({winform.edit.text;winform.edit2.text}) + winform.close() + }else{ + winform.msgbox("请输入信息!")} + +} + +winform.show(); +win.loopMessage(); +return winform; \ No newline at end of file diff --git a/hb_daq/lib/config.aardio b/hb_daq/lib/config.aardio new file mode 100644 index 0000000..a1cbfc5 --- /dev/null +++ b/hb_daq/lib/config.aardio @@ -0,0 +1,20 @@ +//config 配置文件 +import fsys.config; +config = fsys.config("/config/"); +//config = fsys.config( io.appData("/软件作者/应用程序名/") ); + +//不需要序列化的配置名字前请添加下划线 +namespace config { + __appName = "应用程序名"; + __appVersion = "1.0.0.01"; + __appDescription = "这是一个测试程序"; + __website = "http://www.aardio.com/"; +} + +/**intellisense(config) +__appName = 应用程序名 +__appVersion = 应用程序内部版本号 +__appDescription = 程序说明 +__website = 官方网站 +? = 配置文件名,\n读写配置并序列化为一个表对象,\n表的成员值可以是支持序列化的普通变量,支持table对象\n配置文件在首次使用时自动加载,退出程序时自动保存\n!fsys_table. +end intellisense**/ \ No newline at end of file diff --git a/hb_daq/main.aardio b/hb_daq/main.aardio new file mode 100644 index 0000000..ab39ff1 --- /dev/null +++ b/hb_daq/main.aardio @@ -0,0 +1,208 @@ +import win.ui; +import win.inputBox; +import win.ui.menu; +import win.util.tray; +import win.ui.atom; +import win.timer; +import console; +import win.timer; +import fsys; +import web.multipartFormData; +import inet.http; +import fsys.config; +/*DSG{{*/ +mainForm = win.form(text="数据采集";right=799;bottom=399;border="dialog frame";max=false) +mainForm.add( +add={cls="button";text="新建";left=27;top=130;right=98;bottom=154;font=LOGFONT(h=-14;name='微软雅黑');z=6}; +backupPath={cls="edit";left=107;top=58;right=337;bottom=84;edge=1;font=LOGFONT(h=-14;name='微软雅黑');z=11}; +backupPathLabel={cls="static";text="备份文件夹";left=31;top=60;right=118;bottom=81;font=LOGFONT(h=-14;name='微软雅黑');notify=1;transparent=1;z=10}; +groupbox={cls="groupbox";text="采集内容";left=18;top=110;right=346;bottom=390;edge=1;z=5}; +groupbox2={cls="groupbox";text="采集日志";left=353;top=7;right=792;bottom=390;ah=1;aw=1;db=1;dr=1;edge=1;z=1}; +groupbox3={cls="groupbox";text="基础配置";left=18;top=7;right=346;bottom=102;edge=1;z=2}; +listbox={cls="listbox";left=360;top=24;right=785;bottom=387;edge=1;hscroll=1;items={};vscroll=1;z=12}; +listview={cls="listview";left=27;top=161;right=337;bottom=384;edge=1;fullRow=1;items={};msel=false;z=7}; +serverUrl={cls="edit";left=107;top=25;right=337;bottom=51;edge=1;font=LOGFONT(h=-14;name='微软雅黑');z=4}; +serverUrlLabel={cls="static";text="服务器地址";left=31;top=28;right=118;bottom=49;font=LOGFONT(h=-14;name='微软雅黑');notify=1;transparent=1;z=3}; +start={cls="button";text="开始采集";left=266;top=130;right=337;bottom=154;font=LOGFONT(h=-14;name='微软雅黑');z=8}; +statusLabel={cls="static";left=143;top=130;right=221;bottom=154;align="center";color=32768;font=LOGFONT(h=-16;name='微软雅黑';weight=700);transparent=1;z=9} +) +/*}}*/ + +/* +inputbox = win.inputBox(mainForm.hwnd) +inputbox.text = "输入框标题" +inputbox.info.text = "请在下面输入您的名字" +inputbox.input.text = "在这里输入您的名字" +name = inputbox.doModal(); + +if(name) + win.msgbox("您的名字是:"+name ) +else + win.msgbox("你拒绝输入名字") +*/ +mainForm.listview.adjust = function(cx,cy){ + mainForm.listview.fillParent(/*列序号*/); +} + +mainForm.listview.insertColumn("设备编号",100,,0x0/*_LVCFMT_LEFT*/) +mainForm.listview.insertColumn("文件夹地址",100,,0x0/*_LVCFMT_LEFT*/) //第二列开始可以使用_LVCFMT_CENTER居中 + +config = fsys.config("/config/") +mainForm.bindConfig( config.winform,{ + serverUrl = "text"; + backupPath = "text"; + listview = "items"; +} ); +if(mainForm.serverUrl.text==""){ + mainForm.serverUrl.text='http://127.0.0.1:8000' +} +if(mainForm.backupPath.text==""){ + mainForm.backupPath.text="D:\Daq\Backup" +} +/* +if(table.count(mainForm.listview.items)==0){ + mainForm.listview.items = {{"JN102";"D:\tmp"}}; +} +*/ + +var isWorking = false; +var atom,hwnd/*冲突窗口的句柄,该函数会自动激活此窗口*/ = mainForm.atom("33D501DF-BFC2-4283-8BBE-AF17AADB1C27"); +if(!atom){ + /*为窗口设置原子值可以避免一个程序重复运行多个实例*/ + win.quitMessage(); return; +} + + +mainForm.onMinimize = function(lParam){ + var tray = win.util.tray(mainForm) //创建托盘图标 + tray.tip = "数据采集"; + mainForm.show(false); //隐藏窗口 + return true;//阻击默认消息传递,取消最小化过程 +} +mainForm.wndproc = { + [0xACCF/*_WM_TRAYMESSAGE*/ ] = function(hwnd,message,wParam,lParam){ + if( lParam = 0x205/*_WM_RBUTTONUP*/ ){ + var pt = ::POINT(); + ::User32.GetCursorPos(pt); + //弹出托盘菜单以前,一定要前置主窗口中,不然不点击菜单不会消失 + win.setForeground(mainForm.hwnd) + mainForm.popmenu.popup(pt.x,pt.y,true ) + }elseif(lParam = 0x203/*_WM_LBUTTONDBLCLK*/){ + mainForm.show() + } + + + } +} + +mainForm.popmenu = win.ui.popmenu(mainForm);//创建弹出菜单 +mainForm.popmenu.add('&打开',function(id){ + //在下面输入菜单响应代码 + mainForm.show() +}); +mainForm.popmenu.add();//分隔线 +mainForm.popmenu.add('&退出',function(id){ mainForm.close() }) + +mainForm.start.oncommand = function(id,event){ + toggleWorking(); + +} +var timer = win.timer( mainForm ); +timer.setInterval(5000) +function toggleWorking(){ + if(isWorking == false){ + mainForm.serverUrl.disabled = true + mainForm.backupPath.disabled = true + mainForm.add.disabled = true + mainForm.statusLabel.text="采集中..." + mainForm.start.text="停止采集" + isWorking = true + timer.enable() + }else{ + mainForm.serverUrl.disabled = false + mainForm.backupPath.disabled = false + mainForm.add.disabled = false + mainForm.statusLabel.text="" + mainForm.start.text="开始采集" + isWorking=false + timer.disable() + } +} +if(mainForm.serverUrl && table.count(mainForm.listview.items)>0){ +toggleWorking(); +} + +timer.onTimer = function(hwnd,msg,id,tick){ + for itemIndex in mainForm.listview.each(){ + var number, dir = mainForm.listview.items[itemIndex][1], mainForm.listview.items[itemIndex][2] + //批量处理文件 + fsys.enum( dir, //指定要遍历的目录 + "*.*", //指定查询文件名,支持windows掩码 + function(dir,filename,fullpath,findData){ //指定触发器 + if(filename){ + mainForm.listbox.add(tostring(time.now(),"%Y-%m-%d %H:%M:%S","chs") + ":新文件-"+filename, -1) + mainForm.listbox.add("正在上传并解析...") + var webData = web.multipartFormData(); + webData.add("equip_num", number) + webData.add("file", "@"+fullpath) + webData.contentHeader() + var http = inet.http(); + /* +http.beginRequest( mainForm.serverUrl.text + "/api/em/daq/", "POST" ); + //小数据一次性上传 + http.beginSendData(webData.size()); + http.writeData(webData.readAll()) + http.endSendData(); +*/ + var html,err,errCode = http.post( mainForm.serverUrl.text + "/api/em/daq/",webData.readAll(),webData.contentHeader()); + if(html){ + var res = web.json.parse(html) + if(res['code']==200){ + import fsys + var theDir = fsys.createDir(mainForm.backupPath.text+"\"+number, false) + fsys.move(fullpath, theDir) //移动到备份文件库 + mainForm.listbox.add("采集成功!") + }else{ + mainForm.listbox.add("失败:"+res['msg']) + } + }else{ + mainForm.listbox.add("失败:请求错误") + } + + + + } + }, false + ); + } +} + +mainForm.listview.onnotify = function(id,code,ptr){ + + select(code) { + case 0xFFFFFFFB/*_NM_RCLICK*/ { + var x,y = win.getCursorPos(); + var popmenu = win.ui.popmenu(mainForm);//创建弹出菜单 + popmenu.add('删除',function(id){ + //在下面输入菜单响应代码 + mainForm.listview.delItem( mainForm.listview.selIndex ) + }); + popmenu.popup(x,y,true);//弹出菜单 + } + } + +} + +mainForm.add.oncommand = function(id,event){ + +var frmChild = mainForm.loadForm("\dlg\add.aardio"); +frmChild.doModal(); + +} + + + + + +mainForm.show(); +return win.loopMessage(); \ No newline at end of file diff --git a/hb_server/apps/em/serializers.py b/hb_server/apps/em/serializers.py index b17e860..a200114 100644 --- a/hb_server/apps/em/serializers.py +++ b/hb_server/apps/em/serializers.py @@ -1,3 +1,4 @@ +from rest_framework import serializers from rest_framework.serializers import ModelSerializer from .models import Equipment,Equipmentrecord @@ -34,4 +35,8 @@ class EquipmentrecordSerializer(ModelSerializer): def setup_eager_loading(queryset): """ Perform necessary eager loading of data. """ queryset = queryset.select_related('equipment') - return queryset \ No newline at end of file + return queryset + +class DaqCreateSerializer(serializers.Serializer): + number = serializers.CharField() + file = serializers.FileField() \ No newline at end of file diff --git a/hb_server/apps/em/urls.py b/hb_server/apps/em/urls.py index a2f58d8..e2f7e91 100644 --- a/hb_server/apps/em/urls.py +++ b/hb_server/apps/em/urls.py @@ -1,6 +1,6 @@ from django.db.models import base from rest_framework import urlpatterns -from apps.em.views import EquipmentViewSet,EquipmentrecordViewSet +from apps.em.views import DaqView, EquipmentViewSet,EquipmentrecordViewSet from django.urls import path, include from rest_framework.routers import DefaultRouter @@ -8,6 +8,7 @@ router = DefaultRouter() router.register('equipment', EquipmentViewSet, basename='equipment') router.register('equipmentrecord', EquipmentrecordViewSet, basename='equipmentrecord') urlpatterns = [ + path('daq/', DaqView.as_view()), path('', include(router.urls)), ] diff --git a/hb_server/apps/em/views.py b/hb_server/apps/em/views.py index 64ad57d..00ae4b9 100644 --- a/hb_server/apps/em/views.py +++ b/hb_server/apps/em/views.py @@ -1,10 +1,12 @@ from django.shortcuts import render +from rest_framework.exceptions import APIException +from rest_framework.views import APIView from rest_framework.viewsets import ModelViewSet from rest_framework import serializers, status from rest_framework.response import Response from apps.em.models import Equipment,Equipmentrecord -from apps.em.serializers import EquipmentSerializer,EquipmentrecordSerializer +from apps.em.serializers import DaqCreateSerializer, EquipmentSerializer,EquipmentrecordSerializer from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin @@ -57,4 +59,28 @@ class EquipmentrecordViewSet(CreateUpdateModelAMixin, OptimizationMixin, ModelVi serializer = self.get_serializer(id, data=data) serializer.is_valid(raise_exception=True) serializer.save() - return Response(status=status.HTTP_200_OK) \ No newline at end of file + return Response(status=status.HTTP_200_OK) + +import uuid +import os +from django.conf import settings +from rest_framework.parsers import MultiPartParser +class DaqView(APIView): + """ + 数据采集 + """ + authentication_classes = [] + permission_classes = [] + parser_classes = [MultiPartParser] + + def post(self, request, format=None): + data = request.data + file = data.get('file', None) + equip_num = data.get('equip_num', None) + filename = str(uuid.uuid4()) + filepath = settings.BASE_DIR +'/temp/' + filename + os.path.splitext(file.name)[-1] + with open(filepath, 'wb') as f: + for chunk in file.chunks(): + f.write(chunk) + return Response() + # raise APIException('解析失败') \ No newline at end of file diff --git a/hb_server/apps/mtm/serializers.py b/hb_server/apps/mtm/serializers.py index 68b214b..004d3d3 100644 --- a/hb_server/apps/mtm/serializers.py +++ b/hb_server/apps/mtm/serializers.py @@ -25,7 +25,7 @@ class MaterialDetailSerializer(serializers.ModelSerializer): class MaterialSimpleSerializer(serializers.ModelSerializer): class Meta: model = Material - fields = ['id', 'name', 'number', 'unit'] + fields = ['id', 'name', 'number', 'unit','specification'] class ProcessSerializer(serializers.ModelSerializer): instruction_ = FileSimpleSerializer(source='instruction', read_only=True) diff --git a/hb_server/apps/mtm/views.py b/hb_server/apps/mtm/views.py index c58ed9f..317575c 100644 --- a/hb_server/apps/mtm/views.py +++ b/hb_server/apps/mtm/views.py @@ -100,7 +100,7 @@ class InputMaterialViewSet(CreateUpdateModelAMixin, ModelViewSet): perms_map = {'*':'*'} queryset = InputMaterial.objects.select_related('material').all() serializer_class = InputMaterialSerializer - filterset_fields = ['process', 'material'] + filterset_fields = ['process', 'product'] ordering = ['sort', '-create_time'] def get_serializer_class(self): @@ -117,7 +117,7 @@ class OutputMaterialViewSet(CreateUpdateModelAMixin, ModelViewSet): perms_map = {'*':'*'} queryset = OutputMaterial.objects.select_related('material').all() serializer_class = OutputMaterialSerializer - filterset_fields = ['process', 'material'] + filterset_fields = ['process', 'product'] ordering = ['sort', '-create_time'] def get_serializer_class(self): diff --git a/hb_server/apps/sam/migrations/0003_contract_invoice.py b/hb_server/apps/sam/migrations/0003_contract_invoice.py new file mode 100644 index 0000000..d4031f3 --- /dev/null +++ b/hb_server/apps/sam/migrations/0003_contract_invoice.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.6 on 2021-09-22 01:42 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('sam', '0002_auto_20210913_0954'), + ] + + operations = [ + migrations.AddField( + model_name='contract', + name='invoice', + field=models.IntegerField(default=0, verbose_name='开票金额'), + ), + ] diff --git a/hb_server/apps/sam/models.py b/hb_server/apps/sam/models.py index b03e471..4683844 100644 --- a/hb_server/apps/sam/models.py +++ b/hb_server/apps/sam/models.py @@ -31,9 +31,17 @@ class Contract(CommonAModel): """ 合同信息 """ + state_choices = ( + (0, '完好'), + (1, '限用'), + (2, '在修'), + (3, '禁用') + ) name = models.CharField('合同名称', max_length=100) number = models.CharField('合同编号', max_length=100, unique=True) amount = models.IntegerField('合同金额', default=0) + invoice = models.IntegerField('开票金额', default=0) + #state = models.CharField('合同状态', choices= state_choices, max_length=20, default=1) customer = models.ForeignKey(Customer, verbose_name='关联客户', on_delete=models.CASCADE, related_name='contact_customer') sign_date = models.DateField('签订日期') description = models.CharField('描述', max_length=200, blank=True, null=True)