Merge branch 'develop' of https://e.coding.net/ctcdevteam/hberp/hberp into develop

This commit is contained in:
shijing 2021-11-23 10:01:16 +08:00
commit 8e37c13f06
12 changed files with 215 additions and 22 deletions

View File

@ -0,0 +1,27 @@
from django_filters import rest_framework as filters
from apps.mtm.models import Material, Step
from apps.pm.models import SubProductionProgress
from apps.wpm.models import Operation, WProduct
from apps.wpm.services import WpmServies
class SubproductionProgressFilterSet(filters.FilterSet):
operation = filters.NumberFilter(method='filter_operation')
class Meta:
model = SubProductionProgress
fields = ['material', 'subproduction_plan', 'operation', 'type']
def filter_operation(self, queryset, name, value):
operation = Operation.objects.get(pk=value)
wproducts = WProduct.objects.filter(ow_wproduct__operation=value)
step = operation.step
if wproducts.exists():
subplans = WpmServies.get_subplans_queryset_from_wproducts(wproducts)
else:
subplans = WpmServies.get_subplans_queyset_from_step(step)
queryset = queryset.filter(subproduction_plan__in=subplans)
if step.type == Step.STEP_TYPE_NOM:
queryset = queryset.exclude(material__type=Material.MA_TYPE_HALFGOOD)
return queryset

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.9 on 2021-11-22 07:56
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('pm', '0014_subproductionplan_number'),
]
operations = [
migrations.AddField(
model_name='subproductionplan',
name='main_count_ok',
field=models.IntegerField(default=0, verbose_name='合格数'),
),
migrations.AddField(
model_name='subproductionprogress',
name='count_ok',
field=models.IntegerField(default=0, verbose_name='合格数量'),
),
]

View File

@ -56,6 +56,7 @@ class SubProductionPlan(CommonAModel):
main_product = models.ForeignKey(Material, verbose_name='主要产品', on_delete=models.CASCADE, null=True, blank=True) main_product = models.ForeignKey(Material, verbose_name='主要产品', on_delete=models.CASCADE, null=True, blank=True)
main_count = models.IntegerField('应产出数', default=0) main_count = models.IntegerField('应产出数', default=0)
main_count_real = models.IntegerField('实际产出数', default=0) main_count_real = models.IntegerField('实际产出数', default=0)
main_count_ok = models.IntegerField('合格数', default=0)
steps = models.JSONField('工艺步骤', default=list) steps = models.JSONField('工艺步骤', default=list)
@ -80,3 +81,4 @@ class SubProductionProgress(BaseModel):
count = models.IntegerField('应出入数') count = models.IntegerField('应出入数')
count_pick = models.IntegerField('实际领用数', default=0) count_pick = models.IntegerField('实际领用数', default=0)
count_real = models.IntegerField('实际消耗/产出数', default=0) count_real = models.IntegerField('实际消耗/产出数', default=0)
count_ok = models.IntegerField('合格数量', default=0)

View File

@ -1,4 +1,4 @@
from apps.pm.views import ProductionPlanViewSet, ResourceViewSet, SubProductionPlanViewSet from apps.pm.views import ProductionPlanViewSet, ResourceViewSet, SubProductionPlanViewSet, SubProductionProgressViewSet
from django.db.models import base from django.db.models import base
from rest_framework import urlpatterns from rest_framework import urlpatterns
from django.urls import path, include from django.urls import path, include
@ -7,6 +7,7 @@ from rest_framework.routers import DefaultRouter
router = DefaultRouter() router = DefaultRouter()
router.register('production_plan', ProductionPlanViewSet, basename='production_plan') router.register('production_plan', ProductionPlanViewSet, basename='production_plan')
router.register('subproduction_plan', SubProductionPlanViewSet, basename='subproduction_plan') router.register('subproduction_plan', SubProductionPlanViewSet, basename='subproduction_plan')
router.register('subproduction_progress', SubProductionProgressViewSet, basename='subproduction_progress')
router.register('resource', ResourceViewSet, basename='resource') router.register('resource', ResourceViewSet, basename='resource')
urlpatterns = [ urlpatterns = [
path('', include(router.urls)), path('', include(router.urls)),

View File

@ -1,4 +1,5 @@
from datetime import timezone from datetime import timezone
from typing import List
from django.db import transaction from django.db import transaction
from rest_framework import serializers from rest_framework import serializers
from rest_framework.views import APIView from rest_framework.views import APIView
@ -7,6 +8,7 @@ from apps.em.serializers import EquipmentSerializer
from apps.inm.models import MaterialBatch from apps.inm.models import MaterialBatch
from apps.inm.serializers import MaterialBatchSerializer from apps.inm.serializers import MaterialBatchSerializer
from apps.mtm.models import Step, SubProduction, SubprodctionMaterial, UsedStep from apps.mtm.models import Step, SubProduction, SubprodctionMaterial, UsedStep
from apps.pm.filters import SubproductionProgressFilterSet
from apps.system.mixins import CreateUpdateModelAMixin from apps.system.mixins import CreateUpdateModelAMixin
from apps.pm.serializers import GenSubPlanSerializer, PickNeedSerializer, PlanDestorySerializer, ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer, ResourceCalListSerializer, ResourceCalSerializer, SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer from apps.pm.serializers import GenSubPlanSerializer, PickNeedSerializer, PlanDestorySerializer, ProductionPlanCreateFromOrderSerializer, ProductionPlanSerializer, ResourceCalListSerializer, ResourceCalSerializer, SubProductionPlanListSerializer, SubProductionPlanUpdateSerializer, SubProductionProgressSerializer
from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelMixin from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelMixin
@ -67,7 +69,7 @@ class ProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, CreateModel
return Response() return Response()
@action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=PlanDestorySerializer) @action(methods=['post'], detail=False, perms_map={'post':'*'}, serializer_class=PlanDestorySerializer)
def destory(self, request, pk=None): def deletes(self, request, pk=None):
""" """
批量物理删除 批量物理删除
""" """
@ -178,6 +180,17 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
have = MaterialBatchSerializer(instance=objs, many=True).data have = MaterialBatchSerializer(instance=objs, many=True).data
return Response({'need':need, 'have':have}) return Response({'need':need, 'have':have})
class SubProductionProgressViewSet(ListModelMixin, GenericViewSet):
"""
生产进度
"""
perms_map = {'*': '*'}
queryset = SubProductionProgress.objects.select_related('material', 'subproduction_plan')
search_fields = []
serializer_class = SubProductionProgressSerializer
filterset_class = SubproductionProgressFilterSet
ordering_fields = ['id']
ordering = ['id']
class ResourceViewSet(GenericViewSet): class ResourceViewSet(GenericViewSet):

View File

@ -1,4 +1,7 @@
from django_filters import rest_framework as filters from django_filters import rest_framework as filters
from apps.mtm.models import Material, Step
from apps.wpm.services import WpmServies
from .models import Operation, WMaterial, WProduct from .models import Operation, WMaterial, WProduct
class WMaterialFilterSet(filters.FilterSet): class WMaterialFilterSet(filters.FilterSet):
@ -6,12 +9,15 @@ class WMaterialFilterSet(filters.FilterSet):
operation = filters.NumberFilter(method='filter_operation') operation = filters.NumberFilter(method='filter_operation')
class Meta: class Meta:
model = WMaterial model = WMaterial
fields = ['material', 'subproduction_plan', 'subproduction_plan__process', 'subproduction_plan__workshop'] fields = ['material', 'subproduction_plan', 'subproduction_plan__process', 'subproduction_plan__workshop', 'operation']
def filter_operation(self, queryset, name, value): def filter_operation(self, queryset, name, value):
operation = Operation.objects.get(pk=value) operation = Operation.objects.get(pk=value)
wproducts = WProduct.objects.filter(ow_wproduct__operation=value) wproducts = WProduct.objects.filter(ow_wproduct__operation=value)
step = operation.step
if wproducts.exists(): if wproducts.exists():
pass subplans = WpmServies.get_subplans_queryset_from_wproducts(wproducts)
else: else:
pass subplans = WpmServies.get_subplans_queyset_from_step(step)
queryset = queryset.filter(subproduction_plan__in=subplans).exclude(material__type=Material.MA_TYPE_HALFGOOD)
return queryset

View File

@ -0,0 +1,19 @@
# Generated by Django 3.2.9 on 2021-11-22 07:56
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('wpm', '0019_auto_20211122_1110'),
]
operations = [
migrations.AlterField(
model_name='operationwproduct',
name='wproduct',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ow_wproduct', to='wpm.wproduct', verbose_name='关联半成品'),
),
]

View File

@ -0,0 +1,21 @@
# Generated by Django 3.2.9 on 2021-11-23 01:45
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('wpm', '0020_alter_operationwproduct_wproduct'),
]
operations = [
migrations.RemoveField(
model_name='operationwproduct',
name='production_plan',
),
migrations.RemoveField(
model_name='wproduct',
name='production_plan',
),
]

View File

@ -43,7 +43,6 @@ class WProduct(CommonAModel):
parent = models.JSONField('', default=list, blank=True) parent = models.JSONField('', default=list, blank=True)
remark = models.CharField('备注', max_length=200, null=True, blank=True) remark = models.CharField('备注', max_length=200, null=True, blank=True)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE, related_name='wproduct_subplan') subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE, related_name='wproduct_subplan')
production_plan = models.ForeignKey(ProductionPlan, verbose_name='关联主生产计划', on_delete=models.CASCADE)
warehouse = models.ForeignKey(WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True) warehouse = models.ForeignKey(WareHouse, verbose_name='所在仓库', on_delete=models.SET_NULL, null=True, blank=True)
operation = models.ForeignKey('wpm.operation', verbose_name='关联操作', operation = models.ForeignKey('wpm.operation', verbose_name='关联操作',
on_delete=models.SET_NULL, null=True, blank=True, related_name='current_operation') on_delete=models.SET_NULL, null=True, blank=True, related_name='current_operation')
@ -66,7 +65,6 @@ class OperationWproduct(BaseModel):
number = models.CharField('物品编号', null=True, blank=True, max_length=50) number = models.CharField('物品编号', null=True, blank=True, max_length=50)
material = models.ForeignKey(Material, verbose_name='操作时的物料状态', on_delete=models.CASCADE) material = models.ForeignKey(Material, verbose_name='操作时的物料状态', on_delete=models.CASCADE)
subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE) subproduction_plan = models.ForeignKey(SubProductionPlan, verbose_name='当前子生产计划', on_delete=models.CASCADE)
production_plan = models.ForeignKey(ProductionPlan, verbose_name='当前主生产计划', on_delete=models.CASCADE)
class OperationMaterial(BaseModel): class OperationMaterial(BaseModel):

View File

@ -326,12 +326,13 @@ class OperationMaterialCreate1Serailizer(serializers.ModelSerializer):
class Meta: class Meta:
model = OperationMaterial model = OperationMaterial
fields = ['operation', 'wmaterial', 'count'] fields = ['operation', 'wmaterial', 'count']
def create(self, validated_data): def create(self, validated_data):
wmaterial = validated_data['wmaterial'] wmaterial = validated_data['wmaterial']
validated_data['material'] = wmaterial.material validated_data['material'] = wmaterial.material
validated_data['subproduction_plan'] = wmaterial.subproduction_plan validated_data['subproduction_plan'] = wmaterial.subproduction_plan
validated_data['batch'] = wmaterial.batch validated_data['batch'] = wmaterial.batch
validated_data['type'] = SubprodctionMaterial.SUB_MA_TYPE_IN
return super().create(validated_data) return super().create(validated_data)
class OperationMaterialCreate2Serailizer(serializers.ModelSerializer): class OperationMaterialCreate2Serailizer(serializers.ModelSerializer):
@ -344,6 +345,7 @@ class OperationMaterialCreate2Serailizer(serializers.ModelSerializer):
subproduction_progress = validated_data['subproduction_progress'] subproduction_progress = validated_data['subproduction_progress']
validated_data['material'] = subproduction_progress.material validated_data['material'] = subproduction_progress.material
validated_data['subproduction_plan'] = subproduction_progress.subproduction_plan validated_data['subproduction_plan'] = subproduction_progress.subproduction_plan
validated_data['type'] = SubprodctionMaterial.SUB_MA_TYPE_OUT
return super().create(validated_data) return super().create(validated_data)
class OperationMaterialCreate3Serializer(serializers.ModelSerializer): class OperationMaterialCreate3Serializer(serializers.ModelSerializer):
@ -351,5 +353,9 @@ class OperationMaterialCreate3Serializer(serializers.ModelSerializer):
class Meta: class Meta:
model = OperationMaterial model = OperationMaterial
fields = ['operation', 'material'] fields = ['operation', 'material']
def create(self, validated_data):
validated_data['type'] = SubprodctionMaterial.SUB_MA_TYPE_TOOL
return super().create(validated_data)

View File

@ -69,7 +69,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
wps = WProduct.objects.filter(pk__in=[x for x in i['wproducts']]) wps = WProduct.objects.filter(pk__in=[x for x in i['wproducts']])
wps.update(step=first_step, is_executed=False, wps.update(step=first_step, is_executed=False,
act_state=WProduct.WPR_ACT_STATE_DOING, is_hidden=False, warehouse=None, act_state=WProduct.WPR_ACT_STATE_DOING, is_hidden=False, warehouse=None,
subproduction_plan=sp, production_plan=sp.production_plan, update_by=request.user, update_time=timezone.now()) subproduction_plan=sp, update_by=request.user, update_time=timezone.now())
return Response() return Response()
@ -84,7 +84,7 @@ class WPlanViewSet(ListModelMixin, GenericViewSet):
vdata = serializer.data vdata = serializer.data
subplan = self.get_object() subplan = self.get_object()
material = subplan.main_product material = subplan.main_product
batch = subplan.production_plan.number batch = subplan.number
warehouse = WareHouse.objects.get(id=vdata['warehouse']) warehouse = WareHouse.objects.get(id=vdata['warehouse'])
wproducts = WProduct.objects.filter(subproduction_plan=subplan, wproducts = WProduct.objects.filter(subproduction_plan=subplan,
act_state=WProduct.WPR_ACT_STATE_OK, material=material, is_deleted=False) act_state=WProduct.WPR_ACT_STATE_OK, material=material, is_deleted=False)
@ -160,7 +160,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
perms_map={'*':'*'} perms_map={'*':'*'}
queryset = WProduct.objects.select_related('step', 'material').filter(is_hidden=False).exclude(operation=None) queryset = WProduct.objects.select_related('step', 'material').filter(is_hidden=False).exclude(operation=None)
serializer_class = WProductListSerializer serializer_class = WProductListSerializer
filterset_fields = ['step', 'subproduction_plan', 'material', 'production_plan', 'step__process', 'act_state'] filterset_fields = ['step', 'subproduction_plan', 'material', 'step__process', 'act_state']
search_fields = ['number'] search_fields = ['number']
ordering_fields = ['id'] ordering_fields = ['id']
ordering = ['id'] ordering = ['id']
@ -207,7 +207,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
# 更新子计划主产品数 # 更新子计划主产品数
instance = SubProductionProgress.objects.get(subproduction_plan=wproduct.subproduction_plan, instance = SubProductionProgress.objects.get(subproduction_plan=wproduct.subproduction_plan,
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT) is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
instance.count_real = instance.count_real + 1 # 这个地方可能会有问题 instance.count_ok = instance.count_ok + 1 # 这个地方可能会有问题
instance.save() instance.save()
else:# 如果不合格 else:# 如果不合格
pass pass
@ -228,7 +228,7 @@ class WProductViewSet(ListModelMixin, GenericViewSet):
if wproduct.act_state != WProduct.WPR_ACT_STATE_OK: if wproduct.act_state != WProduct.WPR_ACT_STATE_OK:
raise exceptions.APIException('半成品不可入库') raise exceptions.APIException('半成品不可入库')
material = wproduct.material material = wproduct.material
batch = wproduct.production_plan.number batch = wproduct.subproduction_plan.number
# 创建入库记录 # 创建入库记录
remark = vdata.get('remark', '') remark = vdata.get('remark', '')
fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_IN, fifo = FIFO.objects.create(type=FIFO.FIFO_TYPE_DO_IN,
@ -314,7 +314,6 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
owp['number'] = wpd.number owp['number'] = wpd.number
owp['material'] = wpd.material owp['material'] = wpd.material
owp['subproduction_plan'] = wpd.subproduction_plan owp['subproduction_plan'] = wpd.subproduction_plan
owp['production_plan'] = wpd.production_plan
owps.append(OperationWproduct(**owp)) owps.append(OperationWproduct(**owp))
OperationWproduct.objects.bulk_create(owps) OperationWproduct.objects.bulk_create(owps)
else: else:
@ -343,9 +342,90 @@ class OperationViewSet(ListModelMixin, RetrieveModelMixin, CreateModelMixin, Upd
opm.save() opm.save()
return Response() return Response()
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer)
@transaction.atomic
def submit(self, request, pk=None):
"""
提交车间操作重要
"""
op = self.get_object()
step = op.step
# 检查自定义表单填写
if OperationRecord.objects.filter(operation=op, is_filled=False).exists():
raise exceptions.APIException('存在自定义表单未填写')
# 更新物料消耗进度
for i in OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_IN):
# 更新车间物料
i_wmat = i.wmaterial
i_wmat.count = i_wmat.count- i['count']
i_wmat.save()
# 更新子计划物料消耗情况
sp = i_wmat.subproduction_plan
sp.count_real = sp.count_real + i['count']
sp.save()
# 更新产出
for i in OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_OUT):
if not i.subproduction_progress.is_main:
# 更新车间物料产出情况
ins, _ = WMaterial.objects.get_or_create(subproduction_plan=i.subproduction_plan,
material=i.material)
ins.count = ins.count + i['count']
ins.save()
# 更新子计划物料产出情况
sp = i.subproduction_progress
sp.count_real = sp.count_real + i['count']
sp.save()
# 更新动态产品表
if step.type == Step.STEP_TYPE_NOM:
for i in OperationWproduct.objects.filter(operation=op):
wp = i.wproduct
wsp = i.subproduction_plan
# 获取下一步子工序
newstep, hasNext = WpmServies.get_next_step(wsp, step)
wp.step = newstep
wp.pre_step = step
if hasNext:
wp.is_executed= False
else:
wp.is_executed = True
wp.act_state = WProduct.WPR_ACT_STATE_TOTEST
wp.material = wsp.main_product
# 更新子计划进度
instance = SubProductionProgress.objects.get(subproduction_plan=wsp,
is_main=True, type=SubprodctionMaterial.SUB_MA_TYPE_OUT)
instance.count_real = instance.count_real + 1 # 这个地方可能会有问题,不够严谨
instance.save()
wp.operation = None
wp.save()
elif step.type == Step.STEP_TYPE_DIV:
# 更新物料产出情况
for i in OperationMaterial.objects.filter(operation=op, type=SubprodctionMaterial.SUB_MA_TYPE_OUT):
if i.subproduction_progress.is_main:
newstep, _ = WpmServies.get_next_step(i.subproduction_plan, step)
wpr = dict(material=i.material, step=newstep,
act_state=WProduct.WPR_ACT_STATE_DOING, is_executed=False, remark='',
subproduction_plan=i.subproduction_plan)
for x in range(i.count):
WProduct.objects.create(**wpr)
elif step.type == Step.STEP_TYPE_COMB:
# 隐藏原半成品
ows = OperationWproduct.objects.filter(operation=op)
ows.update(is_hidden=True)
if i.subproduction_progress.is_main:
newstep, hasNext = WpmServies.get_next_step(i.subproduction_plan, step)
wproduct = WProduct()
wproduct.material = i.material
wproduct.step = newstep
wproduct.subproduction_plan = i.subproduction_plan
wproduct.parent = ows.values_list('wproduct', flat=True)
if hasNext:
wproduct.act_state = WProduct.WPR_ACT_STATE_DOING
wproduct.is_executed = False
else:
wproduct.act_state = WProduct.WPR_ACT_STATE_TOTEST
wproduct.is_executed = True
wproduct.save()
class OperationWproductViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet): class OperationWproductViewSet(ListModelMixin, DestroyModelMixin, GenericViewSet):
@ -581,7 +661,6 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
owp['number'] = wp.number owp['number'] = wp.number
owp['material'] = wp.material owp['material'] = wp.material
owp['subproduction_plan'] = wp.subproduction_plan owp['subproduction_plan'] = wp.subproduction_plan
owp['production_plan'] = wp.production_plan
owps.append(OperationWproduct(**owp)) owps.append(OperationWproduct(**owp))
OperationWproduct.objects.bulk_create(owps) OperationWproduct.objects.bulk_create(owps)
@ -611,8 +690,7 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
newstep, _ = WpmServies.get_next_step(i['subproduction_plan'], vdata['step']) newstep, _ = WpmServies.get_next_step(i['subproduction_plan'], vdata['step'])
wpr = dict(material=ma, step=newstep, wpr = dict(material=ma, step=newstep,
act_state=WProduct.WPR_ACT_STATE_DOING, is_executed=False, remark='', act_state=WProduct.WPR_ACT_STATE_DOING, is_executed=False, remark='',
subproduction_plan=i['subproduction_plan'], subproduction_plan=i['subproduction_plan'])
production_plan=i['subproduction_plan'].production_plan)
for x in range(i['count_output']): for x in range(i['count_output']):
WProduct.objects.create(**wpr) WProduct.objects.create(**wpr)
else: else:
@ -641,7 +719,6 @@ class DoFormSubmit(CreateAPIView, GenericAPIView):
wproduct.material = vdata['subproduction_plan'].main_product wproduct.material = vdata['subproduction_plan'].main_product
wproduct.step = newstep wproduct.step = newstep
wproduct.subproduction_plan=vdata['subproduction_plan'] wproduct.subproduction_plan=vdata['subproduction_plan']
wproduct.production_plan=vdata['subproduction_plan'].production_plan
wproduct.parent = data['wproducts'] wproduct.parent = data['wproducts']
if hasNext: if hasNext:
wproduct.act_state=WProduct.WPR_ACT_STATE_DOING wproduct.act_state=WProduct.WPR_ACT_STATE_DOING

View File

@ -62,7 +62,7 @@ class UpdateDevelop(APIView):
import os import os
# 更新后端 # 更新后端
os.chdir('/home/hberp') os.chdir('/home/hberp')
ret = os.popen('git pull https://caoqianming%40ctc.ac.cn:9093qqww@e.coding.net/ctcdevteam/hberp/hberp.git origin develop') ret = os.popen('git pull https://caoqianming%40ctc.ac.cn:9093qqww@e.coding.net/ctcdevteam/hberp/hberp.git develop')
# 打包前端 # 打包前端
# os.chdir('/home/hberp/hb_client') # os.chdir('/home/hberp/hb_client')
# os.system('npm run build:prod') # os.system('npm run build:prod')