This commit is contained in:
““shijing 2021-09-08 11:10:57 +08:00
commit 7dc90e6c45
25 changed files with 1073 additions and 504 deletions

View File

@ -269,3 +269,33 @@ export function deleterffield(id, data) {
data data
}) })
} }
//技术文件
export function gettechdocList(query) {
return request({
url: '/mtm/techdoc/',
method: 'get',
params: query
})
}
export function createtechdoc(data) {
return request({
url: '/mtm/techdoc/',
method: 'post',
data
})
}
export function updatetechdoc(id, data) {
return request({
url: `/mtm/techdoc/${id}/`,
method: 'put',
data
})
}
export function deletetechdoc(id, data) {
return request({
url: `/mtm/techdoc/${id}/`,
method: 'delete',
data
})
}

View File

@ -24,7 +24,7 @@ export default {
}, },
data() { data() {
return { return {
title: 'Django Vue Admin', title: '航玻生产管理系统',
logo: 'https://wpimg.wallstcn.com/69a1c46c-eb1c-4b46-8bd4-e9e686ef5251.png' logo: 'https://wpimg.wallstcn.com/69a1c46c-eb1c-4b46-8bd4-e9e686ef5251.png'
} }
} }

View File

@ -26,7 +26,7 @@
</div> </div>
<div style="margin-top: 10px"> <div style="margin-top: 10px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate" <el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增设备</el-button >新增仓库</el-button
> >
</div> </div>
</el-card> </el-card>

View File

@ -178,7 +178,7 @@ export default {
}, },
options: [{ options: [{
value: 1, value: 1,
label: '' label: ''
}, { }, {
value: 2, value: 2,
label: '半成品' label: '半成品'

View File

@ -167,7 +167,7 @@ export default {
}, },
methods: { methods: {
checkPermission, checkPermission,
//物料列表 //工序列表
getList() { getList() {
this.listLoading = true; this.listLoading = true;
getProcessList(this.listQuery).then((response) => { getProcessList(this.listQuery).then((response) => {

View File

@ -2,7 +2,12 @@
<div class="app-container"> <div class="app-container">
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="6" > <el-col :span="6" >
<el-card style="margin-top: 10px"> <el-card >
<div slot="header" class="clearfix">
<span style="font-size: 16px;
font-weight: 700;
">产品列表</span>
</div>
<el-table <el-table
v-loading="listLoading" v-loading="listLoading"
:data="materialList.results" :data="materialList.results"
@ -29,7 +34,6 @@
</el-col> </el-col>
<el-col :span="18" > <el-col :span="18" >
<el-card class="box-card"> <el-card class="box-card">
<div slot="header" class="clearfix">
<el-descriptions class="margin-top" title="产品信息" :column="3" border> <el-descriptions class="margin-top" title="产品信息" :column="3" border>
@ -50,11 +54,15 @@
</el-descriptions-item> </el-descriptions-item>
</el-descriptions> </el-descriptions>
</div>
</el-card> </el-card>
<el-card class="box-card"> <el-card class="box-card">
<div slot="header" class="clearfix">
<el-steps :active="values" spac="400px" align-center="" style="padding-top: 40px;"> <span style="font-size: 16px;
font-weight: 700;
">工艺流程</span>
</div>
<el-steps :active="values" spac="400px" align-center="" style="padding-top: 20px;">
<el-step :title="item.name" v-for="(item,index) in processoptions " :key="index" @click.native=stepclick(item.id)> <el-step :title="item.name" v-for="(item,index) in processoptions " :key="index" @click.native=stepclick(item.id)>
</el-step> </el-step>
@ -65,29 +73,29 @@
<el-tab-pane label="输入物料"> <el-tab-pane label="输入物料">
<el-button type="primary" icon="el-icon-plus" @click="handleinputCreate" <el-button type="primary" icon="el-icon-plus" @click="handleinputCreate"
>新增</el-button> >新增</el-button>
<el-table <el-table
:data="inputtableData.results" :data="inputtableData"
border border
fit fit
stripe stripe
highlight-current-row style="width: 100%"
v-el-height-adaptive-table="{bottomOffset: 50}"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="物料编号"> <el-table-column label="物料编号" min-width="100">
<template slot-scope="scope">{{scope.row.material_.number}}</template> <template slot-scope="scope">{{scope.row.material_.number}}</template>
</el-table-column> </el-table-column>
<el-table-column label="物料名称"> <el-table-column label="物料名称" min-width="100">
<template slot-scope="scope"> {{scope.row.material_.name}}</template> <template slot-scope="scope"> {{scope.row.material_.name}}</template>
</el-table-column> </el-table-column>
<el-table-column label="计量单位"> <el-table-column label="计量单位" min-width="100">
<template slot-scope="scope">{{ scope.row.material_.unit }}</template> <template slot-scope="scope">{{ scope.row.material_.unit }}</template>
</el-table-column> </el-table-column>
<el-table-column label="单位消耗量"> <el-table-column label="单位消耗量" min-width="100">
<template slot-scope="scope">{{ scope.row.count }}</template> <template slot-scope="scope">{{ scope.row.count }}</template>
</el-table-column> </el-table-column>
@ -96,7 +104,6 @@
<el-table-column <el-table-column
align="center" align="center"
label="操作" label="操作"
width="220px"
> >
<template slot-scope="scope"> <template slot-scope="scope">
@ -161,12 +168,10 @@
>新增</el-button> >新增</el-button>
<el-table <el-table
:data="outputtableData.results" :data="outputtableData"
border border
fit fit
stripe stripe
highlight-current-row
v-el-height-adaptive-table="{bottomOffset: 50}"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="物料编号"> <el-table-column label="物料编号">
@ -255,12 +260,10 @@
>新增</el-button> >新增</el-button>
<el-table <el-table
:data="usedsteptableData.results" :data="usedsteptableData"
border border
fit fit
stripe stripe
highlight-current-row
v-el-height-adaptive-table="{bottomOffset: 50}"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
@ -268,12 +271,12 @@
<el-table-column label="子工序名称"> <el-table-column label="子工序名称">
<template slot-scope="scope">{{ scope.row.step_.name }}</template> <template slot-scope="scope">{{ scope.row.step_.name }}</template>
</el-table-column> </el-table-column >
<el-table-column <el-table-column
align="center" align="center"
label="操作" label="操作"
width="220px"
> >
<template slot-scope="scope"> <template slot-scope="scope">
@ -329,8 +332,88 @@
>新增</el-button> >新增</el-button>
</el-tab-pane> </el-tab-pane>
<el-tab-pane label="技术文件"> <el-tab-pane label="技术文件">
<el-button type="primary" icon="el-icon-plus" <el-button type="primary" icon="el-icon-plus" @click="handletechdocCreate"
>新增</el-button> >新增</el-button>
<el-table
:data="techdoctableData"
border
fit
stripe
highlight-current-row
>
<el-table-column type="index" width="50" />
<el-table-column label="文件名称">
<template slot-scope="scope">{{ scope.row.name }}</template>
</el-table-column>
<el-table-column align="center" label="文件">
<template slot-scope="scope" v-if="scope.row.file_">
<el-link :href="scope.row.file_.path" >{{scope.row.file_.name}}</el-link>
</template>
</el-table-column>
<el-table-column
align="center"
label="操作"
width="220px"
>
<template slot-scope="scope">
<el-link
v-if="checkPermission(['process_update'])"
@click="handletechdocEdit(scope)"
>编辑</el-link
>
<el-link
v-if="checkPermission(['process_delete'])"
type="danger"
@click="handletechdocDelete(scope)"
>删除</el-link
>
</template>
</el-table-column>
</el-table>
<el-dialog
:visible.sync="dialogVisiblet"
:title="dialogTypet === 'edit' ? '编辑文件' : '新增文件'"
>
<el-form
ref="Formt"
:model="techdoc"
label-width="100px"
label-position="right"
>
<el-form-item label="文件名称" prop="name">
<el-input v-model="techdoc.name" placeholder="工序名称" />
</el-form-item>
<el-form-item label="内容" prop="content">
<el-input type="textarea" :rows="6" v-model="techdoc.content" placeholder="内容" />
</el-form-item>
<el-form-item label="文件" prop="template" v-if="dialogVisiblet">
<el-upload
ref="upload"
:action="upUrl"
:on-preview="handlePreview"
:on-success="handleUpSuccess"
:on-remove="handleRemove"
:headers="upHeaders"
:file-list="fileList"
:limit="1"
accept=".doc,.docx,.xls,.xlsx,.ppt,.pptx"
>
<el-button size="small" type="primary">上传文件</el-button>
</el-upload>
</el-form-item>
</el-form>
<div style="text-align: right">
<el-button type="danger" @click="dialogVisiblet = false">取消</el-button>
<el-button type="primary" @click="techdocconfirm('Formt')">确认</el-button>
</div>
</el-dialog>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
</el-col> </el-col>
@ -340,8 +423,9 @@
<script> <script>
import { getMaterialList,getMaterial,getInputmaterialList,createInputmaterial,updateInputmaterial import { getMaterialList,getMaterial,getInputmaterialList,createInputmaterial,updateInputmaterial
,deleteInputmaterial,getOutputmaterialList,createOutputmaterial,updateOutputmaterial,deleteOutputmaterial, ,deleteInputmaterial,getOutputmaterialList,createOutputmaterial,updateOutputmaterial,deleteOutputmaterial,
getUsedstepList,createUsedstep,deleteUsedstep,getStepList } from "@/api/mtm"; getUsedstepList,createUsedstep,deleteUsedstep,getStepList,gettechdocList,createtechdoc,updatetechdoc,deletetechdoc } from "@/api/mtm";
import { upUrl, upHeaders } from "@/api/file";
import checkPermission from "@/utils/permission"; import checkPermission from "@/utils/permission";
import { genTree } from "@/utils"; import { genTree } from "@/utils";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
@ -353,6 +437,9 @@ const defaultoutputmaterial = {
}; };
const defaultusedstep = { const defaultusedstep = {
};
const defaulttechdoc = {
}; };
export default { export default {
@ -361,16 +448,20 @@ export default {
data() { data() {
return { return {
materialoptions:[], materialoptions:[],
inputtableData:{count: 0}, inputtableData:"",
inputmaterial: defaultinputmaterial, techdoc: defaulttechdoc,
inputmaterial: defaultinputmaterial,
outputtableData:{count: 0}, techdoctableData:"",
outputtableData:"",
outputmaterial: defaultoutputmaterial, outputmaterial: defaultoutputmaterial,
usedsteptableData:{count: 0}, usedsteptableData:"",
usedstep: defaultusedstep, usedstep: defaultusedstep,
materialList: { materialList: {
count: 0, count: 0,
}, },
upHeaders: upHeaders(),
upUrl: upUrl(),
fileList:[],
stepoptions:[], stepoptions:[],
processoptions:[], processoptions:[],
listQuery: { listQuery: {
@ -378,18 +469,18 @@ export default {
page_size: 20, page_size: 20,
}, },
listQueryinput: { listQueryinput: {
page: 1, page: 0,
page_size: 20,
}, },
listQueryoutput: { listQueryoutput: {
page: 1, page: 0,
page_size: 20,
}, },
listQueryusedstep: { listQueryusedstep: {
page: 1, page: 0,
page_size: 20,
}, },
values:1, listQuerytechdoc:{
page: 0,
},
values:7,
products:"", products:"",
dialogType: "new", dialogType: "new",
dialogVisible:false, dialogVisible:false,
@ -397,6 +488,8 @@ export default {
dialogVisible1:false, dialogVisible1:false,
dialogTypeusedstep: "new", dialogTypeusedstep: "new",
dialogVisibleusedstep:false, dialogVisibleusedstep:false,
dialogTypet: "new",
dialogVisiblet:false,
listLoading: true, listLoading: true,
}; };
@ -452,13 +545,14 @@ export default {
stepclick(id) stepclick(id)
{ {
this.process = id; this.process = id;
alert(this.process) // alert(this.process)
this.getInputmaterialLists(); this.getInputmaterialLists();
this.getmaterialList(); this.getmaterialList();
this.getOutputmaterialLists(); this.getOutputmaterialLists();
this.getstepList(); this.getstepList();
this. getUsedstepLists(); this. getUsedstepLists();
this.gettechdocLists();
}, },
@ -471,6 +565,7 @@ export default {
this.listQueryinput.process=this.process; this.listQueryinput.process=this.process;
this.listQueryinput.product=this.product this.listQueryinput.product=this.product
//this.listQueryinput.page=0;
getInputmaterialList(this.listQueryinput).then((response) => { getInputmaterialList(this.listQueryinput).then((response) => {
if (response.data) { if (response.data) {
@ -551,6 +646,7 @@ export default {
this.listQueryoutput.process=this.process; this.listQueryoutput.process=this.process;
this.listQueryoutput.product=this.product this.listQueryoutput.product=this.product
// this.listQueryoutput.page=0;
getOutputmaterialList(this.listQueryoutput).then((response) => { getOutputmaterialList(this.listQueryoutput).then((response) => {
if (response.data) { if (response.data) {
@ -630,6 +726,7 @@ export default {
this.listQueryusedstep.process=this.process; this.listQueryusedstep.process=this.process;
this.listQueryusedstep.product=this.product this.listQueryusedstep.product=this.product
// this.listQueryusedstep.page=0;
getUsedstepList(this.listQueryusedstep).then((response) => { getUsedstepList(this.listQueryusedstep).then((response) => {
if (response.data) { if (response.data) {
@ -651,7 +748,7 @@ export default {
handlesearch(scope) { handlesearch(scope) {
this.$router.push({name: "StepDo", params: { id: scope.row.step_.id }, }) this.$router.push({name: "Step", params: { id: scope.row.step_.id }, })
}, },
@ -664,6 +761,8 @@ export default {
this.$refs["Formusedstep"].clearValidate(); this.$refs["Formusedstep"].clearValidate();
}); });
}, },
handleusedstepEdit(scope) { handleusedstepEdit(scope) {
this.outputmaterial = Object.assign({}, scope.row); // copy obj this.outputmaterial = Object.assign({}, scope.row); // copy obj
this.dialogType1 = "edit"; this.dialogType1 = "edit";
@ -700,30 +799,103 @@ export default {
} }
}); });
}, },
//技术文件
gettechdocLists(){
this.listQuerytechdoc.process=this.process;
this.listQuerytechdoc.product=this.product;
// this.listQuerytechdoc.page=0;
gettechdocList(this.listQuerytechdoc).then((response) => {
if (response.data) {
this.techdoctableData = response.data;//技术文件
}
})
},
handletechdocCreate(){
this.techdoc = Object.assign({}, defaulttechdoc);
this.dialogTypet = "new";
this.dialogVisiblet = true;
this.fileList=[];
this.$nextTick(() => {
this.$refs["Formt"].clearValidate();
});
},
handlePreview(file) {
if ("url" in file) {
window.open(file.url);
} else {
window.open(file.response.data.path);
}
},
handleUpSuccess(res, file, filelist) {
this.techdoc.file = res.data.id;
},
handleRemove(file, filelist){
this.techdoc.file = null;
},
handletechdocEdit(scope) {
this.techdoc = Object.assign({}, scope.row); // copy obj
this.dialogTypet = "edit";
this.dialogVisiblet = true;
if (this.techdoc.file) {
this.fileList = [
{
name:this.techdoc.file_.name,
url: this.techdoc.file_.path,
},
];
}
this.$nextTick(() => {
this.$refs["Formt"].clearValidate();
});
},
handletechdocDelete(scope) {
this.$confirm("确认删除?", "警告", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "error",
})
.then(async () => {
await deletetechdoc(scope.row.id);
this.gettechdocLists();
this.$message.success("成功");
})
.catch((err) => {
console.error(err);
});
},
async techdocconfirm(form) {
this.$refs[form].validate((valid) => {
if (valid) {
const isEdit = this.dialogTypet === "edit";
if (isEdit) {
updatetechdoc(this.techdoc.id, this.techdoc).then((res) => {
if (res.code >= 200) {
this.gettechdocLists();
this.dialogVisiblet = false;
this.$message.success("成功");
}
});
} else {
this.techdoc.process=this.process;
this.techdoc.product=this.product;
createtechdoc(this.techdoc).then((res) => {
if (res.code >= 200) {
this.gettechdocLists();
this.dialogVisiblet = false;
this.$message.success("成功");
}
});
}
} else {
return false;
}
});
},
}, },
}; };
</script> </script>
<style>
.el-col {
border-radius: 4px;
}
.bg-purple-dark {
background: #99a9bf;
}
.bg-purple {
background: #d3dce6;
}
.bg-purple-light {
background: #e5e9f2;
}
.grid-content {
border-radius: 4px;
min-height: 36px;
}
.box-card{
height:130px;
}
</style>

View File

@ -1,7 +1,6 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-card> <el-card>
<div slot="header" class="clearfix"> <div slot="header" class="clearfix">
<span style="font-size: 16px; <span style="font-size: 16px;
font-weight: 700; font-weight: 700;
@ -80,6 +79,7 @@
:label="item.label" :label="item.label"
:value="item.value"> :value="item.value">
</el-option> </el-option>
<<<<<<< HEAD
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="指导书内容" prop="instruction_content"> <el-form-item label="指导书内容" prop="instruction_content">
@ -296,7 +296,6 @@
import { upUrl, upHeaders } from "@/api/file"; import { upUrl, upHeaders } from "@/api/file";
import { getStep,getrecordformList,createrecordform,updaterecordform,deleterecordform,getrffieldList,createrffield,updaterffield, import { getStep,getrecordformList,createrecordform,updaterecordform,deleterecordform,getrffieldList,createrffield,updaterffield,
deleterffield} from "@/api/mtm"; deleterffield} from "@/api/mtm";
import vueJsonEditor from 'vue-json-editor' import vueJsonEditor from 'vue-json-editor'
import { genTree } from "@/utils"; import { genTree } from "@/utils";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
@ -529,8 +528,6 @@
} }
}); });
}, },
handleCurrentChange(row){ handleCurrentChange(row){
this.formID=row.id; this.formID=row.id;
this.fieldLists(); this.fieldLists();

View File

@ -1,465 +1,508 @@
<template> <template>
<div class="app-container"> <div class="app-container">
<el-card> <el-card>
<el-descriptions title="子工序详情" :column="2" border>
<el-descriptions-item label="工序名称" label-class-name="my-label" content-class-name="my-content">{{step.name}}</el-descriptions-item> <el-descriptions title="子工序详情" :column="2" border>
<el-descriptions-item label="步骤编号" label-class-name="my-label" content-class-name="my-content">{{step.number}}</el-descriptions-item> <el-descriptions-item label="工序名称" label-class-name="my-label" content-class-name="my-content">{{stepDO.name}}</el-descriptions-item>
<el-descriptions-item label="相关设备" label-class-name="my-label" :contentStyle="{'text-align': 'left'}"> <el-descriptions-item label="步骤编号" label-class-name="my-label" content-class-name="my-content">{{stepDO.number}}</el-descriptions-item>
<el-tag v-for="item in step.equipments_" <el-descriptions-item label="相关设备" label-class-name="my-label" :contentStyle="{'text-align': 'left'}">
:key="item.number" <el-tag v-for="item in stepDO.equipments_"
:label="item.name" :key="item.number"
:value="item.number">{{item.name}}</el-tag> :label="item.name"
</el-descriptions-item> :value="item.number">{{item.name}}</el-tag>
<el-descriptions-item label="指导书内容" label-class-name="my-label" :contentStyle="{'text-align': 'left'}">{{step.instruction_content}}</el-descriptions-item> </el-descriptions-item>
</el-descriptions> <el-descriptions-item label="指导书内容" label-class-name="my-label" :contentStyle="{'text-align': 'left'}">{{step.instruction_content}}</el-descriptions-item>
</el-descriptions>
</el-card> </el-card>
<el-card> <el-card>
<el-tabs type="border-card"> <el-tabs type="border-card">
<el-tab-pane label="过程记录"> <el-tab-pane label="过程记录">
<el-row :gutter="24"> <el-row :gutter="24">
<el-col :span="6" > <el-col :span="6" >
<el-card style="margin-top: 10px"> <el-card style="margin-top: 10px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate" <el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增</el-button> >新增</el-button>
<el-table <el-table
:data="recordformList.results" :data="recordformList.results"
border border
fit fit
stripe stripe
highlight-current-row highlight-current-row
height="100" height="100"
v-el-height-adaptive-table="{bottomOffset: 50}" v-el-height-adaptive-table="{bottomOffset: 50}"
@current-change="handleCurrentChange" @current-change="handleCurrentChange"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
<el-table-column label="产品信息"> <el-table-column label="表名称">
<template slot-scope="scope">{{ scope.row.name }}</template> <template slot-scope="scope">{{ scope.row.name }}</template>
</el-table-column> </el-table-column>
<el-table-column <el-table-column
align="center" align="center"
label="操作" label="操作"
>
<template slot-scope="scope">
<el-link
v-if="checkPermission(['material_update'])"
@click="handleEdit(scope)"
>编辑</el-link
> >
<el-link <template slot-scope="scope">
v-if="checkPermission(['material_delete'])"
type="danger" <el-link
@click="handleDelete(scope)" v-if="checkPermission(['material_update'])"
>删除</el-link @click="handleEdit(scope)"
>编辑</el-link
>
<el-link
v-if="checkPermission(['material_delete'])"
type="danger"
@click="handleDelete(scope)"
>删除</el-link
>
</template>
</el-table-column>
</el-table>
<el-dialog
:visible.sync="dialogVisible"
:title="dialogType === 'edit' ? '编辑记录表格' : '新增记录表格'"
>
<el-form
ref="Forms"
:model="recordform"
label-width="80px"
label-position="right"
> >
</template>
</el-table-column>
</el-table> <el-form-item label="表格名称" prop="name">
<el-dialog <el-input v-model="recordform.name" placeholder="表格名称" />
:visible.sync="dialogVisible" </el-form-item>
:title="dialogType === 'edit' ? '编辑记录表格' : '新增记录表格'" <el-form-item label="表格类型" prop="type">
> <el-select style="width: 100%" v-model="recordform.type" placeholder="请选择">
<el-form <el-option
ref="Forms" v-for="item in typeoptions"
:model="recordform" :key="item.value"
label-width="80px" :label="item.label"
label-position="right" :value="item.value">
> </el-option>
<el-form-item label="表格名称" prop="name"> </el-select>
<el-input v-model="recordform.name" placeholder="表格名称" /> </el-form-item>
</el-form-item>
<el-form-item label="表格类型" prop="type">
<el-select style="width: 100%" v-model="recordform.type" placeholder="请选择">
<el-option
v-for="item in typeoptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-form> </el-form>
<div style="text-align: right"> <div style="text-align: right">
<el-button type="danger" @click="dialogVisible = false">取消</el-button> <el-button type="danger" @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="recordformconfirm('Forms')">确认</el-button> <el-button type="primary" @click="recordformconfirm('Forms')">确认</el-button>
</div> </div>
</el-dialog> </el-dialog>
</el-card> </el-card>
</el-col> </el-col>
<el-col :span="18" > <el-col :span="18" >
<el-card class="box-card"> <el-card class="box-card">
<el-button type="primary" icon="el-icon-plus" @click="handlefieldCreate" <el-button type="primary" icon="el-icon-plus" @click="handlefieldCreate"
>新增</el-button> >新增</el-button>
<el-table <el-table
:data="fieldList.results"
border
fit
stripe
highlight-current-row
height="100"
v-el-height-adaptive-table="{bottomOffset: 50}"
>
<el-table-column type="index" width="50" />
<el-table-column label="字段类型">
<template slot-scope="scope">{{ options_[scope.row.field_type] }}</template>
</el-table-column>
<el-table-column label="字段名称"> :data="fieldList.results"
<template slot-scope="scope">{{ scope.row.field_name }}</template> border
</el-table-column> fit
stripe
highlight-current-row
height="100"
v-el-height-adaptive-table="{bottomOffset: 50}"
>
<el-table-column type="index" width="50" />
<el-table-column label="字段类型">
<template slot-scope="scope">{{ options_[scope.row.field_type] }}</template>
</el-table-column>
<el-table-column label="字段名称">
<template slot-scope="scope">{{ scope.row.field_name }}</template>
</el-table-column>
<el-table-column label="字段标识">
<template slot-scope="scope">{{ scope.row.field_key }}</template>
</el-table-column>
<el-table-column label="布尔类型显示名">
<template slot-scope="scope">{{ scope.row.boolean_field_display }}</template>
</el-table-column>
<el-table-column label="选项显示名">
<template slot-scope="scope">{{ scope.row.field_choice }}</template>
</el-table-column>
<el-table-column
align="center"
label="操作"
>
<template slot-scope="scope">
<el-link
v-if="checkPermission(['material_update'])"
@click="handlefieldEdit(scope)"
>编辑</el-link
>
<el-link
v-if="checkPermission(['material_delete'])"
type="danger"
@click="handlefieldDelete(scope)"
>删除</el-link
>
</template>
</el-table-column>
</el-table>
<el-dialog
:visible.sync="dialogVisible1"
:title="dialogType1 === 'edit' ? '编辑表格字段' : '新增表格字段'"
>
<el-form
ref="Form"
:model="field"
label-width="80px"
label-position="right"
>
<el-form-item label="字段类型" prop="field_type">
<el-select style="width: 100%" v-model="field.field_type" placeholder="请选择">
<el-option
v-for="item in fieldtypeoptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="字段标识" prop="field_key">
<el-input v-model="field.field_key" placeholder="字段标识" />
</el-form-item>
<el-form-item label="字段名称" prop="field_name">
<el-input v-model="field.field_name" placeholder="字段名称" />
</el-form-item>
<el-form-item label="布尔类型显示名" prop="boolean_field_display">
<vue-json-editor
v-model="field.boolean_field_display"
:showBtns="false"
:mode="'code'"
lang="zh"
/>
</el-form-item>
<el-form-item label="选项" prop="field_choice">
<vue-json-editor
v-model="field.field_choice"
:showBtns="false"
:mode="'code'"
lang="zh"
/>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input v-model="field.sort" placeholder="排序" />
</el-form-item>
</el-form>
<div style="text-align: right">
<el-button type="danger" @click="dialogVisible1 = false">取消</el-button>
<el-button type="primary" @click="fieldconfirm('Form')">确认</el-button>
</div>
</el-dialog>
</el-card>
</el-col>
</el-row>
<el-table-column label="字段标识">
<template slot-scope="scope">{{ scope.row.field_key }}</template>
</el-table-column>
<el-table-column label="布尔类型显示名">
<template slot-scope="scope">{{ scope.row.boolean_field_display }}</template>
</el-table-column>
<el-table-column label="选项显示名">
<template slot-scope="scope">{{ scope.row.field_choice }}</template>
</el-table-column>
<el-table-column
align="center"
label="操作"
>
<template slot-scope="scope">
<el-link
v-if="checkPermission(['material_update'])"
@click="handlefieldEdit(scope)"
>编辑</el-link>
<el-link
v-if="checkPermission(['material_delete'])"
type="danger"
@click="handlefieldDelete(scope)"
>删除</el-link>
</template>
</el-table-column>
</el-table>
</el-card>
</el-col>
</el-row>
<el-dialog :visible.sync="dialogVisible1" :title="dialogType1 === 'edit' ? '编辑表格字段' : '新增表格字段'">
<el-form ref="Form" :model="field" label-width="80px" label-position="right">
<el-form-item label="字段类型" prop="field_type">
<el-select style="width: 100%" v-model="field.field_type" placeholder="请选择">
<el-option
v-for="item in fieldtypeoptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="字段标识" prop="field_key">
<el-input v-model="field.field_key" placeholder="字段标识" onkeyup="value=value.replace(/[^A-Za-z_\/]/ig,'')"/>
</el-form-item>
<el-form-item label="字段名称" prop="field_name">
<el-input v-model="field.field_name" placeholder="字段名称" />
</el-form-item>
<el-form-item label="选项" v-show="field.field_type=='radio'||field.field_type=='checkbox'||field.field_type=='select'||field.field_type=='selects'">
<el-button @click.prevent="addDomain('1')" style="border: none;">
<i class="el-icon-circle-plus-outline"></i>
<span style="font-size:14px;">添加</span>
</el-button>
<el-row v-for="(domain, $index) in options" :key=domain+$index style="margin-bottom: 10px">
<el-col :span="20">
<el-input v-model="options[$index]" auto-complete="off"></el-input>
</el-col>
<el-col :span="3" style="text-align: center" v-if="$index!==0">
<i class="el-icon-remove-outline" @click.prevent="removeDomain($index,'1')" style="color: red;font-size: 16px;"></i>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="排序" prop="sort">
<el-input-number v-model="field.sort" :min="1" placeholder="排序"></el-input-number>
</el-form-item>
</el-form>
<div style="text-align: right">
<el-button type="danger" @click="dialogVisible1 = false">取消</el-button>
<el-button type="primary" @click="fieldconfirm('Form')">确认</el-button>
</div>
</el-dialog>
</el-tab-pane> </el-tab-pane>
</el-tabs> </el-tabs>
</el-card> </el-card>
</div> </div>
</template> </template>
<script> <script>
import { getStep,getrecordformList,createrecordform,updaterecordform,deleterecordform,getrffieldList,createrffield,updaterffield, import { getStep,getrecordformList,createrecordform,updaterecordform,deleterecordform,getrffieldList,createrffield,updaterffield,
deleterffield} from "@/api/mtm"; deleterffield} from "@/api/mtm";
// import vueJsonEditor from 'vue-json-editor'
import checkPermission from "@/utils/permission";
const defaultrecordform = {
}; import vueJsonEditor from 'vue-json-editor'
const defaultfield = { import checkPermission from "@/utils/permission";
const defaultrecordform = {
}; };
export default { const defaultfield = {
name:'stepdo',
// components: { vueJsonEditor }, };
data() { export default {
return { components: { vueJsonEditor },
step:"", name: "stepdo",
recordform: defaultrecordform,
field: { props: ["stepid"],
field_type:'', data() {
field_key:'', return {
field_name:'', stepDO:"",
sort:'', recordform: defaultrecordform,
field_choice:[], field: defaultfield,
}, dialogType: "new",
date:'', dialogVisible:false,
datetime:'', dialogType1: "new",
time:'', dialogVisible1:false,
options:[''], listQueryrecordform: {
dialogType: "new", page: 1,
dialogVisible:false, page_size: 20,
dialogType1: "new", },
dialogVisible1:false, recordformList: {
listQueryrecordform: { count: 0,
page: 1, },
page_size: 20, fieldList: {
}, count: 0,
recordformList: { },
count: 0, listQueryfield: {
}, page: 1,
fieldList: { page_size: 20,
count: 0, },
}, options_: {
listQueryfield: { 'string':'字符串',
page: 1, 'int':'整型',
page_size: 20, 'float': '浮点',
}, 'boolean':'布尔',
options_: { 'date': '日期',
'string':'字符串', 'datetime': '日期时间',
'number':'数字', 'radio': '单选',
'date': '日期', 'checkbox': '多选',
'datetime': '日期时间', 'select': '单选下拉',
'radio': '单选', 'selects': '多选下拉',
'checkbox': '多选', 'textarea': '文本域'
// 'select': '单选下拉', },
// 'selects': '多选下拉', fieldtypeoptions: [{
// 'textarea': '文本域'
},
fieldtypeoptions: [{
value: 'string', value: 'string',
label: '' label: '字符串'
}, },
{ {
value: 'number', value: 'int',
label: '数字' label: '整型'
}, },
{ {
value: 'date', value: 'float',
label: '日期' label: '浮点'
},
{
value: 'boolean',
label: '布尔'
},
{
value: 'date',
label: '日期'
},
{
value: 'datetime',
label: '日期时间'
},
{
value: 'radio',
label: '单选'
},
{
value: 'checkbox',
label: '多选'
},
{
value: 'select',
label: '单选下拉'
},
{
value: 'selects',
label: '多选下拉'
},
{
value: 'textarea',
label: '文本域'
}],
typeoptions: [{
value: 1,
label: '生产记录'
}],
};
},
computed: {},
watch: {
},
created() {
this.getStepD();
this.recordformLists();
},
methods: {
checkPermission,
getStepD()
{
getStep(this.stepid).then((response) => {
if (response.data) {
this.stepDO = response.data;
}
});
}, },
{
value: 'time', handleCurrentChange(row){
label: '时间' this.formID=row.id;
this.fieldLists();
}, },
{ recordformLists()
value: 'datetime', {
label: '日期时间' this.listQueryrecordform.step=this.stepid;
}, getrecordformList(this.listQueryrecordform).then((response) => {
{ if (response.data) {
value: 'radio', this.recordformList = response.data;
label: '单选' }
},
{
value: 'checkbox',
label: '多选'
}
],
typeoptions: [{
value: 1,
label: '生产记录'
}]
};
},
computed: {},
watch: {},
created() {
this.getStepD();
this.recordformLists();
},
methods: {
//添加
addDomain() {
this.options.push('')
},
//删除
removeDomain(index){
this.options.splice(index, 1)
},
checkPermission,
getStepD(){
getStep(this.$route.params.id).then((response) => {
if (response.data) {
this.step = response.data;
}
}); });
}, },
handleCurrentChange(row){
this.formID=row.id;
this.fieldLists();
},
recordformLists()
{
this.listQueryrecordform.step=this.$route.params.id;
getrecordformList(this.listQueryrecordform).then((response) => {
if (response.data) {
this.recordformList = response.data;
}
});
},
fieldLists() fieldLists()
{ {
this.listQueryfield.form=this.formID this.listQueryfield.form=this.formID
getrffieldList(this.listQueryfield).then((response) => { getrffieldList(this.listQueryfield).then((response) => {
if (response.data) { if (response.data) {
this.fieldList = response.data; this.fieldList = response.data;
} }
}); });
}, },
handleCreate() { handleCreate() {
this.recordform = Object.assign({}, defaultrecordform); this.recordform = Object.assign({}, defaultrecordform);
this.dialogType = "new"; this.dialogType = "new";
this.dialogVisible = true; this.dialogVisible = true;
this.$nextTick(() => { this.$nextTick(() => {
this.$refs["Forms"].clearValidate(); this.$refs["Forms"].clearValidate();
}); });
}, },
handlefieldCreate() { handlefieldCreate() {
this.field = Object.assign({}, defaultfield); this.field = Object.assign({}, defaultfield);
this.dialogType1 = "new"; this.dialogType1 = "new";
this.dialogVisible1 = true; this.dialogVisible1 = true;
this.$nextTick(() => { this.$nextTick(() => {
this.$refs["Form"].clearValidate(); this.$refs["Form"].clearValidate();
}); });
}, },
handleEdit(scope) { handleEdit(scope) {
this.recordform = Object.assign({}, scope.row); // copy obj this.recordform = Object.assign({}, scope.row); // copy obj
this.dialogType = "edit"; this.dialogType = "edit";
this.dialogVisible = true; this.dialogVisible = true;
this.$nextTick(() => { this.$nextTick(() => {
this.$refs["Forms"].clearValidate(); this.$refs["Forms"].clearValidate();
}); });
}, },
handlefieldEdit(scope) { handlefieldEdit(scope) {
this.field = Object.assign({}, scope.row); // copy obj this.field = Object.assign({}, scope.row); // copy obj
this.dialogType1 = "edit"; this.dialogType1 = "edit";
this.dialogVisible1 = true; this.dialogVisible1 = true;
this.$nextTick(() => { this.$nextTick(() => {
this.$refs["Form"].clearValidate(); this.$refs["Form"].clearValidate();
}); });
}, },
handleDelete(scope) { handleDelete(scope) {
this.$confirm("确认删除?", "警告", { this.$confirm("确认删除?", "警告", {
confirmButtonText: "确认", confirmButtonText: "确认",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "error", type: "error",
}) })
.then(async () => { .then(async () => {
await deleterecordform(scope.row.id); await deleterecordform(scope.row.id);
this.recordformLists() this.recordformLists()
this.$message.success("成功"); this.$message.success("成功");
}) })
.catch((err) => { .catch((err) => {
console.error(err); console.error(err);
}); });
}, },
handlefieldDelete(scope) { handlefieldDelete(scope) {
this.$confirm("确认删除?", "警告", { this.$confirm("确认删除?", "警告", {
confirmButtonText: "确认", confirmButtonText: "确认",
cancelButtonText: "取消", cancelButtonText: "取消",
type: "error", type: "error",
}) })
.then(async () => { .then(async () => {
await deleterffield(scope.row.id); await deleterffield(scope.row.id);
this.fieldLists() this.fieldLists()
this.$message.success("成功"); this.$message.success("成功");
}) })
.catch((err) => { .catch((err) => {
console.error(err); console.error(err);
}); });
}, },
async recordformconfirm(form) { async recordformconfirm(form) {
this.$refs[form].validate((valid) => { this.$refs[form].validate((valid) => {
if (valid) { if (valid) {
const isEdit = this.dialogType === "edit"; const isEdit = this.dialogType === "edit";
if (isEdit) { if (isEdit) {
this.recordform.step=this.$route.params.id this.recordform.step=this.stepid
updaterecordform(this.recordform.id, this.recordform).then((res) => { updaterecordform(this.recordform.id, this.recordform).then((res) => {
if (res.code >= 200) { if (res.code >= 200) {
this.recordformLists() this.recordformLists()
this.dialogVisible = false; this.dialogVisible = false;
this.$message.success("成功"); this.$message.success("成功");
} }
}); });
} else { } else {
this.recordform.step=this.$route.params.id this.recordform.step=this.stepid
createrecordform(this.recordform).then((res) => { createrecordform(this.recordform).then((res) => {
if (res.code >= 200) { if (res.code >= 200) {
this.recordformLists() this.recordformLists()
this.dialogVisible = false; this.dialogVisible = false;
this.$message.success("成功"); this.$message.success("成功");
}
});
} }
}); } else {
} return false;
} else { }
return false; });
}
});
}, },
async fieldconfirm(form) { async fieldconfirm(form) {
this.$refs[form].validate((valid) => { this.$refs[form].validate((valid) => {
if (valid) { if (valid) {
const isEdit = this.dialogType1 === "edit"; const isEdit = this.dialogType1 === "edit";
if (isEdit) { if (isEdit) {
this.field.form=this.formID this.field.form=this.formID
updaterffield(this.field.id, this.field).then((res) => { updaterffield(this.field.id, this.field).then((res) => {
if (res.code >= 200) { if (res.code >= 200) {
this.fieldLists() this.fieldLists()
this.dialogVisible1 = false; this.dialogVisible1 = false;
this.$message.success("成功"); this.$message.success("成功");
} }
}); });
} else {
this.field.form=this.formID;
this.field.field_choice = this.options;
createrffield(this.field).then((res) => {
if (res.code >= 200) {
this.fieldLists();
this.dialogVisible1 = false;
this.$message.success("成功");
}
});
}
} else { } else {
return false; this.field.form=this.formID
createrffield(this.field).then((res) => {
if (res.code >= 200) {
this.fieldLists()
this.dialogVisible1 = false;
this.$message.success("成功");
}
});
} }
}); } else {
}, return false;
}, }
}; });
},
},
};
</script> </script>
<style> <style>
.my-label { .my-label {

View File

@ -95,7 +95,7 @@
<el-form <el-form
ref="Form" ref="Form"
:model="vendor" :model="vendor"
label-width="80px" label-width="120px"
label-position="right" label-position="right"
:rules="rule1" :rules="rule1"
> >

View File

@ -11,3 +11,4 @@ celerybeat-schedule.bak
celerybeat-schedule.dat celerybeat-schedule.dat
celerybeat-schedule.dir celerybeat-schedule.dir
db.sqlite3 db.sqlite3
temp/

View File

@ -5,6 +5,7 @@ from django.db.models.query import QuerySet
from apps.system.models import CommonAModel, CommonBModel, Organization, User, Dict, File from apps.system.models import CommonAModel, CommonBModel, Organization, User, Dict, File
from utils.model import SoftModel, BaseModel from utils.model import SoftModel, BaseModel
from simple_history.models import HistoricalRecords from simple_history.models import HistoricalRecords
from apps.mtm.models import Material
@ -21,3 +22,28 @@ class WareHouse(CommonAModel):
def __str__(self): def __str__(self):
return self.name return self.name
class Inventory(CommonAModel):
"""
库存表
"""
material = models.ForeignKey(Material, on_delete=models.CASCADE, verbose_name='物料信息')
count = models.IntegerField('数量', default=0)
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
class Meta:
verbose_name = '库存表'
verbose_name_plural = verbose_name
class FIFO(CommonAModel):
"""
出入库记录
"""
type_choices = (
(1, '生产领料'),
(2, '销售提货'),
(3, '采购入库'),
(4, '生产入库')
)
type = models.IntegerField('出入库类型', default=1)

View File

@ -0,0 +1,38 @@
# Generated by Django 3.2.6 on 2021-09-06 08:58
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
('system', '0003_auto_20210812_0909'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('mtm', '0008_auto_20210901_1620'),
]
operations = [
migrations.CreateModel(
name='TechDoc',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('name', models.CharField(max_length=50, verbose_name='名称')),
('content', models.TextField(blank=True, null=True, verbose_name='内容')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='techdoc_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('file', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='system.file', verbose_name='技术文件')),
('process', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.process', verbose_name='关联工序')),
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='关联产品')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='techdoc_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'verbose_name': '技术文件',
'verbose_name_plural': '技术文件',
},
),
]

View File

@ -0,0 +1,23 @@
# Generated by Django 3.2.6 on 2021-09-07 03:11
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mtm', '0009_techdoc'),
]
operations = [
migrations.AlterField(
model_name='recordformfield',
name='boolean_field_display',
field=models.JSONField(blank=True, default=dict, help_text='当为布尔类型时候,可以支持自定义显示形式。{"1":"","0":""}或{"1":"需要","0":"不需要"},注意数字也需要引号', null=True, verbose_name='布尔类型显示名'),
),
migrations.AlterField(
model_name='recordformfield',
name='field_choice',
field=models.JSONField(blank=True, default=dict, help_text='radio,checkbox,select,multiselect类型可供选择的选项格式为json如:{"1":"中国", "2":"美国"},注意数字也需要引号', null=True, verbose_name='radio、checkbox、select的选项'),
),
]

View File

@ -109,9 +109,9 @@ class RecordFormField(CommonAModel):
field_type = models.CharField('类型', max_length=50, choices=field_type_choices) field_type = models.CharField('类型', max_length=50, choices=field_type_choices)
field_key = models.CharField('字段标识', max_length=50, help_text='字段类型请尽量特殊,避免与系统中关键字冲突') field_key = models.CharField('字段标识', max_length=50, help_text='字段类型请尽量特殊,避免与系统中关键字冲突')
field_name = models.CharField('字段名称', max_length=50) field_name = models.CharField('字段名称', max_length=50)
boolean_field_display = models.JSONField('布尔类型显示名', default=dict, blank=True, boolean_field_display = models.JSONField('布尔类型显示名', default=dict, blank=True, null=True,
help_text='当为布尔类型时候,可以支持自定义显示形式。{"1":"","0":""}或{"1":"需要","0":"不需要"},注意数字也需要引号') help_text='当为布尔类型时候,可以支持自定义显示形式。{"1":"","0":""}或{"1":"需要","0":"不需要"},注意数字也需要引号')
field_choice = models.JSONField('radio、checkbox、select的选项', default=dict, blank=True, field_choice = models.JSONField('radio、checkbox、select的选项', default=dict, blank=True, null=True,
help_text='radio,checkbox,select,multiselect类型可供选择的选项格式为json如:{"1":"中国", "2":"美国"},注意数字也需要引号') help_text='radio,checkbox,select,multiselect类型可供选择的选项格式为json如:{"1":"中国", "2":"美国"},注意数字也需要引号')
sort = models.IntegerField('排序号', default=1) sort = models.IntegerField('排序号', default=1)
class Meta: class Meta:
@ -174,3 +174,18 @@ class UsedStep(CommonAModel):
class Meta: class Meta:
verbose_name = '产品生产子工序' verbose_name = '产品生产子工序'
verbose_name_plural = verbose_name verbose_name_plural = verbose_name
class TechDoc(CommonAModel):
"""
技术文件
"""
name = models.CharField('名称', max_length=50)
file = models.ForeignKey(File, verbose_name='技术文件', on_delete=models.CASCADE)
product = models.ForeignKey(Material, verbose_name='关联产品', on_delete=models.CASCADE)
process = models.ForeignKey(Process, verbose_name='关联工序', on_delete=models.CASCADE)
content = models.TextField('内容', null=True, blank=True)
class Meta:
verbose_name = '技术文件'
verbose_name_plural = verbose_name

View File

@ -1,7 +1,7 @@
from apps.em.serializers import EquipmentSerializer, EquipmentSimpleSerializer from apps.em.serializers import EquipmentSerializer, EquipmentSimpleSerializer
from rest_framework import serializers from rest_framework import serializers
from rest_framework.exceptions import ValidationError from rest_framework.exceptions import ValidationError
from .models import InputMaterial, Material, OutputMaterial, Process, ProductProcess, RecordForm, RecordFormField, Step, UsedStep from .models import InputMaterial, Material, OutputMaterial, Process, ProductProcess, RecordForm, RecordFormField, Step, TechDoc, UsedStep
from apps.system.serializers import FileSimpleSerializer, OrganizationSimpleSerializer from apps.system.serializers import FileSimpleSerializer, OrganizationSimpleSerializer
@ -187,3 +187,19 @@ class RecordFormFieldSimpleSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = RecordFormField model = RecordFormField
fields = '__all__' fields = '__all__'
class TechDocListSerializer(serializers.ModelSerializer):
file_ = FileSimpleSerializer(source='file', read_only=True)
class Meta:
model = TechDoc
fields = '__all__'
class TechDocCreateSerializer(serializers.ModelSerializer):
class Meta:
model = TechDoc
fields = ['file', 'product', 'process', 'name', 'content']
class TechDocUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = TechDoc
fields = ['file', 'name', 'content']

View File

@ -1,6 +1,6 @@
from django.db.models import base from django.db.models import base
from rest_framework import urlpatterns from rest_framework import urlpatterns
from apps.mtm.views import InputMaterialViewSet, MaterialViewSet, OutputMaterialViewSet, ProcessViewSet, RecordFormFieldViewSet, RecordFormViewSet, StepViewSet, UsedStepViewSet from apps.mtm.views import InputMaterialViewSet, MaterialViewSet, OutputMaterialViewSet, ProcessViewSet, RecordFormFieldViewSet, RecordFormViewSet, StepViewSet, TechDocViewSet, UsedStepViewSet
from django.urls import path, include from django.urls import path, include
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
@ -14,6 +14,7 @@ router.register('outputmaterial', OutputMaterialViewSet, basename='outputmateria
router.register('usedstep', UsedStepViewSet, basename='usedstep') router.register('usedstep', UsedStepViewSet, basename='usedstep')
router.register('recordform', RecordFormViewSet, basename='recordform') router.register('recordform', RecordFormViewSet, basename='recordform')
router.register('recordform-field', RecordFormFieldViewSet, basename='recordform-field') router.register('recordform-field', RecordFormFieldViewSet, basename='recordform-field')
router.register('techdoc', TechDocViewSet, basename='techdoc')
urlpatterns = [ urlpatterns = [
path('', include(router.urls)), path('', include(router.urls)),
] ]

View File

@ -2,8 +2,8 @@ from django.shortcuts import render
from rest_framework.viewsets import ModelViewSet, GenericViewSet from rest_framework.viewsets import ModelViewSet, GenericViewSet
from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin from rest_framework.mixins import CreateModelMixin, ListModelMixin, UpdateModelMixin, RetrieveModelMixin, DestroyModelMixin
from apps.mtm.models import InputMaterial, Material, OutputMaterial, Process, ProductProcess, RecordForm, RecordFormField, Step, UsedStep from apps.mtm.models import InputMaterial, Material, OutputMaterial, Process, ProductProcess, RecordForm, RecordFormField, Step, TechDoc, UsedStep
from apps.mtm.serializers import InputMaterialListSerializer, InputMaterialSerializer, InputMaterialUpdateSerializer, MaterialDetailSerializer, MaterialSerializer, MaterialSimpleSerializer, OutputMaterialListSerializer, OutputMaterialSerializer, OutputMaterialUpdateSerializer, ProductProcessListSerializer, ProductProcessUpdateSerializer, ProcessSerializer, RecordFormCreateSerializer, RecordFormFieldCreateSerializer, RecordFormFieldSerializer, RecordFormFieldUpdateSerializer, RecordFormSerializer, RecordFormUpdateSerializer, StepDetailSerializer, StepSerializer, UsedStepCreateSerializer, UsedStepListSerializer from apps.mtm.serializers import InputMaterialListSerializer, InputMaterialSerializer, InputMaterialUpdateSerializer, MaterialDetailSerializer, MaterialSerializer, MaterialSimpleSerializer, OutputMaterialListSerializer, OutputMaterialSerializer, OutputMaterialUpdateSerializer, ProductProcessListSerializer, ProductProcessUpdateSerializer, ProcessSerializer, RecordFormCreateSerializer, RecordFormFieldCreateSerializer, RecordFormFieldSerializer, RecordFormFieldUpdateSerializer, RecordFormSerializer, RecordFormUpdateSerializer, StepDetailSerializer, StepSerializer, TechDocCreateSerializer, TechDocListSerializer, TechDocUpdateSerializer, UsedStepCreateSerializer, UsedStepListSerializer
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.response import Response from rest_framework.response import Response
@ -182,3 +182,20 @@ class RecordFormFieldViewSet(OptimizationMixin, CreateUpdateModelAMixin, ModelVi
elif self.action == 'update': elif self.action == 'update':
return RecordFormFieldUpdateSerializer return RecordFormFieldUpdateSerializer
return RecordFormFieldSerializer return RecordFormFieldSerializer
class TechDocViewSet(OptimizationMixin, CreateUpdateModelAMixin, ModelViewSet):
"""
技术文件增删改查
"""
perms_map = {'*':'*'}
queryset = TechDoc.objects.select_related('file').all()
filterset_fields = ['process', 'product']
search_fields = ['name']
ordering = ['-id']
def get_serializer_class(self):
if self.action =='create':
return TechDocCreateSerializer
elif self.action == 'update':
return TechDocUpdateSerializer
return TechDocListSerializer

View File

@ -0,0 +1,90 @@
# Generated by Django 3.2.6 on 2021-09-07 06:09
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('mtm', '0010_auto_20210907_1111'),
]
operations = [
migrations.CreateModel(
name='Contact',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('name', models.CharField(max_length=100, verbose_name='合同名称')),
('number', models.CharField(max_length=100, unique=True, verbose_name='合同编号')),
('amount', models.IntegerField(default=0, verbose_name='合同金额')),
('sign_date', models.DateField(verbose_name='签订日期')),
('description', models.CharField(blank=True, max_length=200, null=True, verbose_name='描述')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='contact_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
],
options={
'verbose_name': '合同信息',
'verbose_name_plural': '合同信息',
},
),
migrations.CreateModel(
name='Customer',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('name', models.CharField(max_length=50, unique=True, verbose_name='客户名称')),
('country', models.CharField(blank=True, max_length=20, null=True, verbose_name='所属国家')),
('address', models.CharField(blank=True, max_length=20, null=True, verbose_name='详细地址')),
('contact', models.CharField(blank=True, max_length=20, null=True, verbose_name='联系人')),
('phone', models.CharField(blank=True, max_length=11, null=True, unique=True, verbose_name='联系电话')),
('description', models.CharField(blank=True, max_length=200, null=True, verbose_name='描述')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='customer_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='customer_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'verbose_name': '客户信息',
'verbose_name_plural': '客户信息',
},
),
migrations.CreateModel(
name='Order',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('create_time', models.DateTimeField(default=django.utils.timezone.now, help_text='创建时间', verbose_name='创建时间')),
('update_time', models.DateTimeField(auto_now=True, help_text='修改时间', verbose_name='修改时间')),
('is_deleted', models.BooleanField(default=False, help_text='删除标记', verbose_name='删除标记')),
('number', models.CharField(max_length=100, verbose_name='订单编号')),
('count', models.IntegerField(default=0, verbose_name='所需数量')),
('delivery_date', models.DateField(verbose_name='交货日期')),
('contact', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='sam.contact', verbose_name='所属合同')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='order_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('customer', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='sam.customer', verbose_name='客户')),
('product', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='mtm.material', verbose_name='所需产品')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='order_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'verbose_name': '订单信息',
'verbose_name_plural': '订单信息',
},
),
migrations.AddField(
model_name='contact',
name='customer',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='contact_customer', to='sam.customer', verbose_name='关联客户'),
),
migrations.AddField(
model_name='contact',
name='update_by',
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='contact_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人'),
),
]

View File

@ -1,3 +1,5 @@
from numpy import product
from apps.system.models import CommonAModel
from django.db import models from django.db import models
from django.contrib.auth.models import AbstractUser from django.contrib.auth.models import AbstractUser
from django.db.models.base import Model from django.db.models.base import Model
@ -6,18 +8,18 @@ from django.db.models.query import QuerySet
from utils.model import SoftModel, BaseModel from utils.model import SoftModel, BaseModel
from simple_history.models import HistoricalRecords from simple_history.models import HistoricalRecords
from apps.mtm.models import Material
class Customer(BaseModel): class Customer(CommonAModel):
""" """
客户信息 客户信息
""" """
name = models.CharField('客户名称', max_length=50, unique=True) name = models.CharField('客户名称', max_length=50, unique=True)
country = models.CharField('所属国家', max_length=20, blank=True, null=True)
address = models.CharField('详细地址', max_length=20, blank=True, null=True) address = models.CharField('详细地址', max_length=20, blank=True, null=True)
contact = models.CharField('联系人', max_length=20, blank=True, null=True) contact = models.CharField('联系人', max_length=20)
contactphone = models.CharField('联系电话', max_length=11,unique=True, blank=True, null=True) contact_phone = models.CharField('联系电话', max_length=11, unique=True)
description = models.CharField('描述', max_length=200, blank=True, null=True) description = models.CharField('描述', max_length=200, blank=True, null=True)
class Meta: class Meta:
@ -27,16 +29,16 @@ class Customer(BaseModel):
def __str__(self): def __str__(self):
return self.name return self.name
class Contact(BaseModel): class Contact(CommonAModel):
""" """
合同信息 合同信息
""" """
name = models.CharField('合同名称', max_length=100) name = models.CharField('合同名称', max_length=100)
number = models.CharField('合同编号', max_length=100, unique=True, blank=True, null=True) number = models.CharField('合同编号', max_length=100, unique=True)
money = models.IntegerField('合同金额', default=0, null=True, blank=True) amount = models.IntegerField('合同金额', default=0)
customer = models.ForeignKey(Customer, verbose_name='关联客户', on_delete=models.CASCADE, related_name='contact_customer') customer = models.ForeignKey(Customer, verbose_name='关联客户', on_delete=models.CASCADE, related_name='contact_customer')
# contactuser = models.CharField('合同签订人', max_length=100, unique=True, blank=True, null=True) # contactuser = models.CharField('合同签订人', max_length=100, unique=True, blank=True, null=True)
date = models.DateField('签订日期', null=True, blank=True) sign_date = models.DateField('签订日期')
description = models.CharField('描述', max_length=200, blank=True, null=True) description = models.CharField('描述', max_length=200, blank=True, null=True)
class Meta: class Meta:
@ -46,11 +48,16 @@ class Contact(BaseModel):
def __str__(self): def __str__(self):
return self.name return self.name
class Order(BaseModel): class Order(CommonAModel):
""" """
订单信息 订单信息
""" """
number = models.CharField('订单编号', max_length=100) number = models.CharField('订单编号', max_length=100)
customer = models.ForeignKey(Customer, verbose_name='客户', on_delete=models.CASCADE)
contact = models.ForeignKey(Contact, verbose_name='所属合同', null=True, blank=True, on_delete=models.SET_NULL)
product = models.ForeignKey(Material, verbose_name='所需产品', on_delete=models.CASCADE)
count = models.IntegerField('所需数量', default=0)
delivery_date = models.DateField('交货日期')
class Meta: class Meta:
verbose_name = '订单信息' verbose_name = '订单信息'
verbose_name_plural = verbose_name verbose_name_plural = verbose_name

View File

@ -0,0 +1,24 @@
from rest_framework import serializers
from .models import Contact, Customer
class CustomerSerializer(serializers.ModelSerializer):
class Meta:
model = Customer
fields = '__all__'
class CustomerCreateUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Customer
fields = ['name', 'address', 'contact', 'contact_phone', 'description']
class ContactSerializer(serializers.ModelSerializer):
class Meta:
model = Contact
fields = '__all__'
class ContactCreateUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Contact
fields = ['name', 'number', 'amount', 'customer', 'sign_date', 'description']

View File

@ -1,3 +1,23 @@
from apps.sam.serializers import CustomerCreateUpdateSerializer, CustomerSerializer
from apps.sam.models import Customer
from rest_framework.viewsets import ModelViewSet
from apps.system.mixins import CreateUpdateCustomMixin
from django.shortcuts import render from django.shortcuts import render
# Create your views here. # Create your views here.
class CustomerViewSet(CreateUpdateCustomMixin, ModelViewSet):
"""
客户-增删改查
"""
perms_map = {'*': '*'}
queryset = Customer.objects.all()
serializer_class = CustomerSerializer
search_fields = ['name', 'contact']
filterset_fields = []
ordering_fields = ['create_time']
ordering = ['-create_time']
def get_serializer_class(self):
if self.action in ['create', 'update']:
return CustomerCreateUpdateSerializer
return CustomerSerializer

View File

@ -197,3 +197,7 @@ class UserCreateSerializer(serializers.ModelSerializer):
if User.objects.filter(phone=phone): if User.objects.filter(phone=phone):
raise serializers.ValidationError('手机号已经被注册') raise serializers.ValidationError('手机号已经被注册')
return phone return phone
class FaceLoginSerializer(serializers.Serializer):
base64 = serializers.CharField()

View File

@ -1,5 +1,5 @@
from django.urls import path, include from django.urls import path, include
from .views import TaskList, UserViewSet, OrganizationViewSet, PermissionViewSet, RoleViewSet, PositionViewSet, TestView, DictTypeViewSet, DictViewSet, PTaskViewSet from .views import FaceLogin, TaskList, UserViewSet, OrganizationViewSet, PermissionViewSet, RoleViewSet, PositionViewSet, TestView, DictTypeViewSet, DictViewSet, PTaskViewSet
from rest_framework import routers from rest_framework import routers
@ -15,5 +15,6 @@ router.register('ptask', PTaskViewSet, basename="ptask")
urlpatterns = [ urlpatterns = [
path('', include(router.urls)), path('', include(router.urls)),
path('task/', TaskList.as_view()), path('task/', TaskList.as_view()),
path('test/', TestView.as_view()) path('test/', TestView.as_view()),
path('facelogin/', FaceLogin.as_view())
] ]

View File

@ -8,6 +8,7 @@ from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import serializers, status from rest_framework import serializers, status
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.filters import OrderingFilter, SearchFilter from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.generics import CreateAPIView
from rest_framework.mixins import (CreateModelMixin, DestroyModelMixin, from rest_framework.mixins import (CreateModelMixin, DestroyModelMixin,
ListModelMixin, RetrieveModelMixin, ListModelMixin, RetrieveModelMixin,
UpdateModelMixin) UpdateModelMixin)
@ -28,7 +29,7 @@ from .models import (Dict, DictType, File, Organization, Permission, Position,
Role, User) Role, User)
from .permission import RbacPermission, get_permission_list from .permission import RbacPermission, get_permission_list
from .permission_data import RbacFilterSet from .permission_data import RbacFilterSet
from .serializers import (DictSerializer, DictTypeSerializer, FileSerializer, from .serializers import (DictSerializer, DictTypeSerializer, FaceLoginSerializer, FileSerializer,
OrganizationSerializer, PermissionSerializer, OrganizationSerializer, PermissionSerializer,
PositionSerializer, RoleSerializer, PTaskSerializer,PTaskCreateUpdateSerializer, PositionSerializer, RoleSerializer, PTaskSerializer,PTaskCreateUpdateSerializer,
UserCreateSerializer, UserListSerializer, UserCreateSerializer, UserListSerializer,
@ -349,3 +350,45 @@ class FileViewSet(CreateModelMixin, DestroyModelMixin, RetrieveModelMixin, ListM
instance = serializer.save(create_by = self.request.user, name=name, size=size, type=type, mime=mime) instance = serializer.save(create_by = self.request.user, name=name, size=size, type=type, mime=mime)
instance.path = settings.MEDIA_URL + instance.file.name instance.path = settings.MEDIA_URL + instance.file.name
instance.save() instance.save()
import face_recognition
import uuid
import base64
import os
def tran64(s):
missing_padding = len(s) % 4
if missing_padding != 0:
s = s+'='* (4 - missing_padding)
return s
class FaceLogin(CreateAPIView):
authentication_classes = []
permission_classes = []
serializer_class = FaceLoginSerializer
def create(self, request, *args, **kwargs):
"""
人脸识别登录
"""
# serializer = FaceLoginSerializer(data=request.data)
# serializer.is_valid(raise_exception=True)
filename = str(uuid.uuid4())
filepath = settings.BASE_DIR +'/temp/' + filename +'.png'
with open(filepath, 'wb') as f:
data = tran64(request.data.get('base64').replace(' ', '+'))
# data = request.data.get('base64')
f.write(base64.urlsafe_b64decode(data))
picture_of_me = face_recognition.load_image_file(settings.BASE_DIR +'/temp/me.png')
my_face_encoding = face_recognition.face_encodings(picture_of_me)[0]
unknown_picture = face_recognition.load_image_file(filepath)
unknown_face_encoding = face_recognition.face_encodings(unknown_picture)[0]
results = face_recognition.compare_faces([my_face_encoding], unknown_face_encoding, tolerance=0.2)
os.remove(filepath)
if results[0] == True:
return Response('这是曹前明')
else:
return Response('这不是曹前明')

View File

@ -53,6 +53,7 @@ INSTALLED_APPS = [
'apps.wf', 'apps.wf',
'apps.mtm', 'apps.mtm',
'apps.inm', 'apps.inm',
'apps.sam'
] ]
MIDDLEWARE = [ MIDDLEWARE = [