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

This commit is contained in:
shijing 2021-09-18 11:34:37 +08:00
commit a95db059bf
40 changed files with 1874 additions and 39 deletions

View File

@ -2,8 +2,8 @@
ENV = 'development' ENV = 'development'
# base api # base api
#VUE_APP_BASE_API = 'http://127.0.0.1:8000/api' VUE_APP_BASE_API = 'http://127.0.0.1:8000/api'
VUE_APP_BASE_API = 'http://47.95.0.242:2222/api' #VUE_APP_BASE_API = 'http://47.95.0.242:2222/api'
# vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable, # vue-cli uses the VUE_CLI_BABEL_TRANSPILE_MODULES environment variable,

View File

@ -18,6 +18,7 @@
"dependencies": { "dependencies": {
"@riophae/vue-treeselect": "^0.4.0", "@riophae/vue-treeselect": "^0.4.0",
"axios": "^0.21.1", "axios": "^0.21.1",
"cache-loader": "^4.1.0",
"compression-webpack-plugin": "^5.0.1", "compression-webpack-plugin": "^5.0.1",
"d3": "^5.14.2", "d3": "^5.14.2",
"dagre-d3": "^0.6.4", "dagre-d3": "^0.6.4",

View File

@ -34,3 +34,37 @@ export function deleteEquipment(id, data) {
data data
}) })
} }
export function getEquipmentrecordList(query) {
return request({
url: '/em/equipmentrecord/',
method: 'get',
params: query
})
}
export function getEquipmentrecordAll() {
return request({
url: '/em/equipmentrecord/',
method: 'get'
})
}
export function createEquipmentrecord(data) {
return request({
url: '/em/equipmentrecord/',
method: 'post',
data
})
}
export function updateEquipmentrecord(id, data) {
return request({
url: `/em/equipmentrecord/${id}/`,
method: 'put',
data
})
}
export function deleteEquipmentrecord(id, data) {
return request({
url: `/em/equipmentrecord/${id}/`,
method: 'delete',
data
})
}

59
hb_client/src/api/qm.js Normal file
View File

@ -0,0 +1,59 @@
import request from '@/utils/request'
//标准规范
export function getStandardList(query) {
return request({
url: '/qm/standard/',
method: 'get',
params: query
})
}
export function createStandard(data) {
return request({
url: '/qm/standard/',
method: 'post',
data
})
}
export function updateStandard(id, data) {
return request({
url: `/qm/standard/${id}/`,
method: 'put',
data
})
}
export function deleteStandard(id, data) {
return request({
url: `/qm/standard/${id}/`,
method: 'delete',
data
})
}
//检测项目
export function getTestitemList(query) {
return request({
url: '/qm/testitem/',
method: 'get',
params: query
})
}
export function createTestitem(data) {
return request({
url: '/qm/testitem/',
method: 'post',
data
})
}
export function updateTestitem(id, data) {
return request({
url: `/qm/testitem/${id}/`,
method: 'put',
data
})
}
export function deleteTestitem(id, data) {
return request({
url: `/qm/testitem/${id}/`,
method: 'delete',
data
})
}

View File

@ -57,3 +57,33 @@ export function deleteContract(id, data) {
data data
}) })
} }
//订单
//合同
export function getOrderList(query) {
return request({
url: '/sam/order/',
method: 'get',
params: query
})
}
export function createOrder(data) {
return request({
url: '/sam/order/',
method: 'post',
data
})
}
export function updateOrder(id, data) {
return request({
url: `/sam/order/${id}/`,
method: 'put',
data
})
}
export function deleteOrder(id, data) {
return request({
url: `/sam/order/${id}/`,
method: 'delete',
data
})
}

View File

@ -143,9 +143,9 @@ export const asyncRoutes = [
meta: { title: '监视和测量设备', icon: 'example', perms: ['index_manage'] } meta: { title: '监视和测量设备', icon: 'example', perms: ['index_manage'] }
}, },
{ {
path: 'equipment', path: 'record',
name: 'equipment', name: 'record',
component: () => import('@/views/em/equipment'), component: () => import('@/views/em/record'),
meta: { title: '校准检定记录', icon: 'example', perms: ['index_manage'] } meta: { title: '校准检定记录', icon: 'example', perms: ['index_manage'] }
}, },
{ {
@ -175,6 +175,35 @@ export const asyncRoutes = [
component: () => import('@/views/sam/contract'), component: () => import('@/views/sam/contract'),
meta: { title: '合同信息', icon: 'example', perms: ['index_manage'] } meta: { title: '合同信息', icon: 'example', perms: ['index_manage'] }
} }
,
{
path: 'order',
name: 'order',
component: () => import('@/views/sam/order'),
meta: { title: '订单信息', icon: 'example', perms: ['index_manage'] }
}
]
}
,
{
path: '/qm',
component: Layout,
redirect: '/qm/standard',
name: 'qm',
meta: { title: '质量管理', icon: 'example', perms: ['equipment_set'] },
children: [
{
path: 'standard',
name: 'standard',
component: () => import('@/views/qm/standard'),
meta: { title: '标准', icon: 'example', perms: ['index_manage'] }
},
{
path: 'testitem',
name: 'testitem',
component: () => import('@/views/qm/testitem'),
meta: { title: '检测项目', icon: 'example', perms: ['index_manage'] }
}
] ]
}, },
{ {

View File

@ -73,7 +73,7 @@
<el-table-column label="校/检状态"> <el-table-column label="校/检状态">
<template slot-scope="scope">{{ state_[scope.row.statedm] }}</template> <template slot-scope="scope">{{ state_[scope.row.statedm] }}</template>
</el-table-column> </el-table-column>
state_
<el-table-column label="保管人"> <el-table-column label="保管人">
<template slot-scope="scope" v-if="scope.row.keeper_">{{ scope.row.keeper_.username }}</template> <template slot-scope="scope" v-if="scope.row.keeper_">{{ scope.row.keeper_.username }}</template>
</el-table-column> </el-table-column>

View File

@ -0,0 +1,336 @@
<template>
<div class="app-container">
<el-card>
<div>
<el-input
v-model="listQuery.search"
placeholder="设备名称/设备编号/备注"
style="width: 300px"
class="filter-item"
@keyup.enter.native="handleFilter"
/>
<el-button
class="filter-item"
type="primary"
icon="el-icon-search"
@click="handleFilter"
>搜索</el-button
>
<el-button
class="filter-item"
type="primary"
icon="el-icon-refresh-left"
@click="resetFilter"
>重置</el-button
>
</div>
<div style="margin-top: 10px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增校准或检定</el-button
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-table
v-loading="listLoading"
:data="equipmentrecordList.results"
border
fit
stripe
highlight-current-row
max-height="600"
>
<el-table-column type="index" width="50" />
<el-table-column label="设备名称">
<template slot-scope="scope">{{ scope.row.equipment_.name }}</template>
</el-table-column>
<el-table-column label="设备编号">
<template slot-scope="scope">{{ scope.row.equipment_.number }}</template>
</el-table-column>
<el-table-column label="型号规格">
<template slot-scope="scope">{{ scope.row.equipment_.model }}</template>
</el-table-column>
<el-table-column label="设备状态">
<template slot-scope="scope">{{ state_[scope.row.equipment_.statedm] }}</template>
</el-table-column>
<el-table-column label="最近一次校准/检定日期">
<template slot-scope="scope">{{ scope.row.recentlydate }}</template>
</el-table-column>
<el-table-column label="下次应校准或检定日期">
<template slot-scope="scope">{{ scope.row.nextdate }}</template>
</el-table-column>
<el-table-column label="备注">
<template slot-scope="scope">{{ scope.row.description }}</template>
</el-table-column>
<el-table-column
align="center"
label="操作"
width="120px"
>
<template slot-scope="scope">
<el-link
v-if="checkPermission(['equipment_update'])"
@click="handleEdit(scope)"
>编辑</el-link
>
<el-link
v-if="checkPermission(['equipment_delete'])"
type="danger"
@click="handleDelete(scope)"
>删除</el-link
>
</template>
</el-table-column>
</el-table>
<pagination
v-show="equipmentrecordList.count > 0"
:total="equipmentrecordList.count"
:page.sync="listQuery.page"
:limit.sync="listQuery.page_size"
@pagination="getList"
/>
</el-card>
<el-dialog
:visible.sync="dialogVisible"
:title="dialogType === 'edit' ? '编辑校准检定' : '新增校准检定'"
>
<el-form
ref="Form"
:model="equipmentrecord"
label-width="120px"
label-position="right"
:rules="rule1"
>
<el-form-item label="校准或检定设备" prop="equipment">
<el-select style="width: 100%" v-model="equipmentrecord.equipment" placeholder="请选择">
<el-option
v-for="item in equipmentoptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="校准或检定状态" prop="state">
<el-select style="width: 100%" v-model="equipmentrecord.state" placeholder="请选择">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-row>
<el-col :span="12">
<el-form-item label="最近一次校准或检定日期" prop="recentlydate">
<el-date-picker
v-model="equipmentrecord.recentlydate"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width: 100%"
>
</el-date-picker>
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="下次应校准或检定日期" prop="nextdate">
<el-date-picker
v-model="equipmentrecord.nextdate"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width: 100%"
>
</el-date-picker>
</el-form-item>
</el-col>
</el-row>
<el-form-item label="备注" prop="description">
<el-input
type="textarea"
:rows="4"
v-model="equipmentrecord.description"
placeholder="备注"
/>
</el-form-item>
</el-form>
<div style="text-align: right">
<el-button type="danger" @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirm('Form')">确认</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getpEquipmentList, createEquipment,updateEquipment,deleteEquipment,
getEquipmentrecordList, createEquipmentrecord,updateEquipmentrecord,deleteEquipmentrecord } from "@/api/equipment";
import { getUserList } from "@/api/user";
import { getOrgList } from "@/api/org";
import checkPermission from "@/utils/permission";
import { genTree } from "@/utils";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
const defaultequipment = {
};
export default {
components: { Pagination },
data() {
return {
equipmentrecord: defaultequipment,
equipmentrecordList: {
count: 0,
},
listQuery: {
page: 1,
page_size: 20,
},
state_:{
0:'合格',
1:'准用',
2:'限用',
3:'禁用',
4:'停用',
5:'封存',
},
options: [{
value: 0,
label: '合格'
}, {
value: 1,
label: '准用'
}, {
value: 2,
label: '限用'
},
{
value: 3,
label: '禁用'
}, {
value: 4,
label: '停用'
}, {
value: 5,
label: '封存'
}],
listLoading: true,
dialogVisible: false,
dialogType: "new",
rule1: {
equipment: [{ required: true, message: "请输入", trigger: "blur" }],
state: [{ required: true, message: "请输入", trigger: "blur" }],
},
};
},
computed: {},
watch: {},
created() {
this.getequipmentList();
this.getList();
},
methods: {
checkPermission,
//设备
getequipmentList() {
getpEquipmentList({pageoff:true,type:2}).then((res) => {
this.equipmentoptions = genTree(res.data);
});
},
getList() {
this.listLoading = true;
getEquipmentrecordList(this.listQuery).then((response) => {
if (response.data) {
this.equipmentrecordList = response.data;
}
this.listLoading = false;
});
},
handleFilter() {
this.listQuery.page = 1;
this.getList();
},
resetFilter() {
this.listQuery = {
page: 1,
page_size: 20,
}
this.getList();
},
handleCreate() {
this.equipmentrecord = Object.assign({}, defaultequipment);
this.dialogType = "new";
this.dialogVisible = true;
this.$nextTick(() => {
this.$refs["Form"].clearValidate();
});
},
handleEdit(scope) {
this.equipmentrecord = Object.assign({}, scope.row); // copy obj
this.dialogType = "edit";
this.dialogVisible = true;
this.$nextTick(() => {
this.$refs["Form"].clearValidate();
});
},
handleDelete(scope) {
this.$confirm("确认删除?", "警告", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "error",
})
.then(async () => {
await deleteEquipmentrecord(scope.row.id);
this.getList();
this.$message.success("成功");
})
.catch((err) => {
console.error(err);
});
},
async confirm(form) {
this.$refs[form].validate((valid) => {
if (valid) {
const isEdit = this.dialogType === "edit";
if (isEdit) {
updateEquipmentrecord(this.equipmentrecord.id, this.equipmentrecord).then((res) => {
if (res.code >= 200) {
this.getList();
this.dialogVisible = false;
this.$message.success("成功");
}
});
} else {
createEquipmentrecord(this.equipmentrecord).then((res) => {
if (res.code >= 200) {
this.getList();
this.dialogVisible = false;
this.$message.success("成功");
}
});
}
} else {
return false;
}
});
},
},
};
</script>

View File

@ -170,6 +170,7 @@ import Pagination from "@/components/Pagination"; // secondary package based on
const defaultmaterial = { const defaultmaterial = {
name: "", name: "",
number: "", number: "",
processes:[],
}; };
export default { export default {
components: { Pagination }, components: { Pagination },

View File

@ -33,7 +33,7 @@
</el-col> </el-col>
<el-col :span="18" > <el-col :span="18" >
<el-card class="box-card"> <el-card >
<el-descriptions class="margin-top" title="产品信息" :column="3" border> <el-descriptions class="margin-top" title="产品信息" :column="3" border>
@ -546,13 +546,12 @@ export default {
{ {
this.process = id; this.process = id;
// alert(this.process) // alert(this.process)
this.getInputmaterialLists(); this.getInputmaterialLists();//输入物料
this.getmaterialList(); this.getOutputmaterialLists();//输出物料
this.getOutputmaterialLists(); this.getstepList();//子工序
this.getstepList(); this. getUsedstepLists();//
this. getUsedstepLists(); this.gettechdocLists();//技术文件
this.gettechdocLists();
}, },

View File

@ -0,0 +1,286 @@
<template>
<div class="app-container">
<el-card>
<div>
<el-input
v-model="listQuery.search"
placeholder="标准名称"
style="width: 300px"
class="filter-item"
@keyup.enter.native="handleFilter"
/>
<el-button
class="filter-item"
type="primary"
icon="el-icon-search"
@click="handleFilter"
>搜索</el-button
>
<el-button
class="filter-item"
type="primary"
icon="el-icon-refresh-left"
@click="resetFilter"
>重置</el-button
>
</div>
<div style="margin-top: 10px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增标准</el-button
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-table
v-loading="listLoading"
:data="standardList.results"
border
fit
stripe
highlight-current-row
max-height="600"
>
<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 label="标准编号">
<template slot-scope="scope">{{ scope.row.number }}</template>
</el-table-column>
<el-table-column label="是否启用">
<template slot-scope="scope">
<el-tag v-if="scope.row.enabled===true"></el-tag>
<el-tag v-else></el-tag>
</template>
</el-table-column>
<el-table-column 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(['warehouse_update'])"
@click="handleEdit(scope)"
>编辑</el-link
>
<el-link
v-if="checkPermission(['warehouse_delete'])"
type="danger"
@click="handleDelete(scope)"
>删除</el-link
>
</template>
</el-table-column>
</el-table>
<pagination
v-show="standardList.count > 0"
:total="standardList.count"
:page.sync="listQuery.page"
:limit.sync="listQuery.page_size"
@pagination="getList"
/>
</el-card>
<el-dialog
:visible.sync="dialogVisible"
:title="dialogType === 'edit' ? '编辑标准' : '新增标准'"
>
<el-form
ref="Form"
:model="standard"
label-width="80px"
label-position="right"
:rules="rule1"
>
<el-form-item label="标准名称" prop="name">
<el-input v-model="standard.name" placeholder="标准名称" />
</el-form-item>
<el-form-item label="标准编号" prop="number">
<el-input v-model="standard.number" placeholder="标准编号" />
</el-form-item>
<el-form-item label="是否启用" prop="enabled">
<el-switch v-model="standard.enabled"></el-switch>
</el-form-item>
<el-form-item label="指导书" prop="template" v-if="dialogVisible">
<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="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirm('Form')">确认</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getStandardList, createStandard,updateStandard,deleteStandard} from "@/api/qm";
import checkPermission from "@/utils/permission";
import { upUrl, upHeaders } from "@/api/file";
import { genTree } from "@/utils";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
const defaultestandard = {
};
export default {
components: { Pagination },
data() {
return {
standard: defaultestandard,
contractList: {
count: 0,
},
upHeaders: upHeaders(),
upUrl: upUrl(),
fileList:[],
listQuery: {
page: 1,
page_size: 20,
},
options:[],
listLoading: true,
dialogVisible: false,
enabled:false,
dialogType: "new",
rule1: {
name: [{ required: true, message: "请输入", trigger: "blur" }],
number: [{ required: true, message: "请输入", trigger: "blur" }],
},
};
},
computed: {},
watch: {},
created() {
this.getList();
},
methods: {
checkPermission,
getList() {
this.listLoading = true;
getStandardList(this.listQuery).then((response) => {
if (response.data) {
this.standardList = response.data;
}
this.listLoading = false;
});
},
handlePreview(file) {
if ("url" in file) {
window.open(file.url);
} else {
window.open(file.response.data.path);
}
},
handleUpSuccess(res, file, filelist) {
this.standard.file = res.data.id;
},
handleRemove(file, filelist){
this.standard.file = null;
},
handleFilter() {
this.listQuery.page = 1;
this.getList();
},
resetFilter() {
this.listQuery = {
page: 1,
page_size: 20,
}
this.getList();
},
handleCreate() {
this.standard = Object.assign({}, defaultestandard);
this.dialogType = "new";
this.dialogVisible = true;
this.fileList=[];
this.$nextTick(() => {
this.$refs["Form"].clearValidate();
});
},
handleEdit(scope) {
this.standard = Object.assign({}, scope.row); // copy obj
this.dialogType = "edit";
this.dialogVisible = true;
if (this.standard.file) {
this.fileList = [
{
name:this.standard.file_.name,
url: this.standard.file_.path,
},
];
}
this.$nextTick(() => {
this.$refs["Form"].clearValidate();
});
},
handleDelete(scope) {
this.$confirm("确认删除?", "警告", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "error",
})
.then(async () => {
await deleteStandard(scope.row.id);
this.getList();
this.$message.success("成功");
})
.catch((err) => {
console.error(err);
});
},
async confirm(form) {
this.$refs[form].validate((valid) => {
if (valid) {
const isEdit = this.dialogType === "edit";
if (isEdit) {
updateStandard(this.standard.id, this.standard).then((res) => {
if (res.code >= 200) {
this.getList();
this.dialogVisible = false;
this.$message.success("成功");
}
});
} else {
createStandard(this.standard).then((res) => {
if (res.code >= 200) {
this.getList();
this.dialogVisible = false;
this.$message.success("成功");
}
});
}
} else {
return false;
}
});
},
},
};
</script>

View File

@ -0,0 +1,258 @@
<template>
<div class="app-container">
<el-card>
<div>
<el-input
v-model="listQuery.search"
placeholder="项目名称"
style="width: 300px"
class="filter-item"
@keyup.enter.native="handleFilter"
/>
<el-button
class="filter-item"
type="primary"
icon="el-icon-search"
@click="handleFilter"
>搜索</el-button
>
<el-button
class="filter-item"
type="primary"
icon="el-icon-refresh-left"
@click="resetFilter"
>重置</el-button
>
</div>
<div style="margin-top: 10px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增项目</el-button
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-table
v-loading="listLoading"
:data="testitemList.results"
border
fit
stripe
highlight-current-row
max-height="600"
>
<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 label="条款号">
<template slot-scope="scope">{{ scope.row.term_number }}</template>
</el-table-column>
<el-table-column label="标准名称">
<template slot-scope="scope">{{ scope.row.standard_.name }}</template>
</el-table-column>
<el-table-column label="标准编号">
<template slot-scope="scope">{{ scope.row.standard_.number }}</template>
</el-table-column>
<el-table-column label="创建时间">
<template slot-scope="scope">{{ scope.row.create_time }}</template>
</el-table-column>
<el-table-column
align="center"
label="操作"
width="220px"
>
<template slot-scope="scope">
<el-link
v-if="checkPermission(['warehouse_update'])"
@click="handleEdit(scope)"
>编辑</el-link
>
<el-link
v-if="checkPermission(['warehouse_delete'])"
type="danger"
@click="handleDelete(scope)"
>删除</el-link
>
</template>
</el-table-column>
</el-table>
<pagination
v-show="testitemList.count > 0"
:total="testitemList.count"
:page.sync="listQuery.page"
:limit.sync="listQuery.page_size"
@pagination="getList"
/>
</el-card>
<el-dialog
:visible.sync="dialogVisible"
:title="dialogType === 'edit' ? '编辑项目' : '新增项目'"
>
<el-form
ref="Form"
:model="testitem"
label-width="80px"
label-position="right"
:rules="rule1"
>
<el-form-item label="项目名称" prop="name">
<el-input v-model="testitem.name" placeholder="项目名称" />
</el-form-item>
<el-form-item label="条款号" prop="term_number">
<el-input v-model="testitem.term_number" placeholder="条款号" />
</el-form-item>
<el-form-item label="标准" prop="standard">
<el-select style="width: 100%" v-model="testitem.standard" placeholder="请选择">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-form>
<div style="text-align: right">
<el-button type="danger" @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirm('Form')">确认</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getTestitemList, createTestitem,updateTestitem,deleteTestitem,getStandardList } from "@/api/qm";
import checkPermission from "@/utils/permission";
import { genTree } from "@/utils";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
const defaultetestitem = {
};
export default {
components: { Pagination },
data() {
return {
testitem: defaultetestitem,
testitemList: {
count: 0,
},
listQuery: {
page: 1,
page_size: 20,
},
options:[],
listLoading: true,
dialogVisible: false,
dialogType: "new",
rule1: {
name: [{ required: true, message: "请输入", trigger: "blur" }],
term_number: [{ required: true, message: "请输入", trigger: "blur" }],
},
};
},
computed: {},
watch: {},
created() {
this.getList();
this.getLists()
},
methods: {
checkPermission,
//列表
getList() {
this.listLoading = true;
getTestitemList(this.listQuery).then((response) => {
if (response.data) {
this.testitemList = response.data;
}
this.listLoading = false;
});
},
getLists() {
getStandardList({pageoff:true}).then((response) => {
this.options = genTree(response.data);
});
},
handleFilter() {
this.listQuery.page = 1;
this.getList();
},
resetFilter() {
this.listQuery = {
page: 1,
page_size: 20,
}
this.getList();
},
handleCreate() {
this.testitem = Object.assign({}, defaultetestitem);
this.dialogType = "new";
this.dialogVisible = true;
this.$nextTick(() => {
this.$refs["Form"].clearValidate();
});
},
handleEdit(scope) {
this.testitem = Object.assign({}, scope.row); // copy obj
this.dialogType = "edit";
this.dialogVisible = true;
this.$nextTick(() => {
this.$refs["Form"].clearValidate();
});
},
handleDelete(scope) {
this.$confirm("确认删除?", "警告", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "error",
})
.then(async () => {
await deleteTestitem(scope.row.id);
this.getList();
this.$message.success("成功");
})
.catch((err) => {
console.error(err);
});
},
async confirm(form) {
this.$refs[form].validate((valid) => {
if (valid) {
const isEdit = this.dialogType === "edit";
if (isEdit) {
updateTestitem(this.testitem.id, this.testitem).then((res) => {
if (res.code >= 200) {
this.getList();
this.dialogVisible = false;
this.$message.success("成功");
}
});
} else {
createTestitem(this.testitem).then((res) => {
if (res.code >= 200) {
this.getList();
this.dialogVisible = false;
this.$message.success("成功");
}
});
}
} else {
return false;
}
});
},
},
};
</script>

View File

@ -33,7 +33,7 @@
<el-card style="margin-top: 10px"> <el-card style="margin-top: 10px">
<el-table <el-table
v-loading="listLoading" v-loading="listLoading"
:data="warehouseList.results" :data="contractList.results"
border border
fit fit
stripe stripe
@ -41,18 +41,21 @@
max-height="600" max-height="600"
> >
<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 label="详细地址"> <el-table-column label="合同编号">
<template slot-scope="scope">{{ scope.row.address }}</template> <template slot-scope="scope">{{ scope.row.number }}</template>
</el-table-column> </el-table-column>
<el-table-column label="联系人"> <el-table-column label="合同金额">
<template slot-scope="scope">{{ scope.row.contact }}</template> <template slot-scope="scope">{{ scope.row.amount }}</template>
</el-table-column> </el-table-column>
<el-table-column label="联系电话"> <el-table-column label="客户名称">
<template slot-scope="scope">{{ scope.row.contact_phone }}</template> <template slot-scope="scope">{{ scope.row.customer_.name }}</template>
</el-table-column>
<el-table-column label="签订日期">
<template slot-scope="scope">{{ scope.row.sign_date }}</template>
</el-table-column> </el-table-column>
<el-table-column label="描述"> <el-table-column label="描述">
<template slot-scope="scope">{{ scope.row.description }}</template> <template slot-scope="scope">{{ scope.row.description }}</template>
@ -82,8 +85,8 @@
</el-table-column> </el-table-column>
</el-table> </el-table>
<pagination <pagination
v-show="warehouseList.count > 0" v-show="contractList.count > 0"
:total="warehouseList.count" :total="contractList.count"
:page.sync="listQuery.page" :page.sync="listQuery.page"
:limit.sync="listQuery.page_size" :limit.sync="listQuery.page_size"
@pagination="getList" @pagination="getList"
@ -111,8 +114,25 @@
</el-form-item> </el-form-item>
<el-form-item label="签订日期" prop="sign_date"> <el-form-item label="签订日期" prop="sign_date">
<el-input v-model="contract.sign_date" placeholder="签订日期" /> <el-date-picker
v-model="contract.sign_date"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width: 100%"
>
</el-date-picker>
</el-form-item> </el-form-item>
<el-form-item label="客户" prop="sign_date">
<el-select style="width: 100%" v-model="contract.customer" placeholder="请选择">
<el-option
v-for="item in options"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="描述" prop="description"> <el-form-item label="描述" prop="description">
<el-input v-model="contract.description" placeholder="描述" /> <el-input v-model="contract.description" placeholder="描述" />
</el-form-item> </el-form-item>
@ -126,7 +146,7 @@
</div> </div>
</template> </template>
<script> <script>
import { getContractList, createContract,updateContract,deleteContract } from "@/api/sam"; import { getContractList, createContract,updateContract,deleteContract,getCustomerList } from "@/api/sam";
import checkPermission from "@/utils/permission"; import checkPermission from "@/utils/permission";
@ -139,14 +159,14 @@ export default {
data() { data() {
return { return {
contract: defaultecontract, contract: defaultecontract,
customerList: { contractList: {
count: 0, count: 0,
}, },
listQuery: { listQuery: {
page: 1, page: 1,
page_size: 20, page_size: 20,
}, },
options:[],
listLoading: true, listLoading: true,
dialogVisible: false, dialogVisible: false,
dialogType: "new", dialogType: "new",
@ -158,22 +178,31 @@ export default {
computed: {}, computed: {},
watch: {}, watch: {},
created() { created() {
this.getLists();
this.getList(); this.getList();
}, },
methods: { methods: {
checkPermission, checkPermission,
//设备列表
getList() { getList() {
this.listLoading = true; this.listLoading = true;
getContractList(this.listQuery).then((response) => { getContractList(this.listQuery).then((response) => {
if (response.data) { if (response.data) {
this.warehouseList = response.data; this.contractList = response.data;
} }
this.listLoading = false; this.listLoading = false;
}); });
}, },
getLists() {
getCustomerList({pageoff:true}).then((response) => {
this.options = genTree(response.data);
});
},
handleFilter() { handleFilter() {
this.listQuery.page = 1; this.listQuery.page = 1;
this.getList(); this.getList();

View File

@ -0,0 +1,317 @@
<template>
<div class="app-container">
<el-card>
<div>
<el-input
v-model="listQuery.search"
placeholder="订单名称"
style="width: 300px"
class="filter-item"
@keyup.enter.native="handleFilter"
/>
<el-button
class="filter-item"
type="primary"
icon="el-icon-search"
@click="handleFilter"
>搜索</el-button
>
<el-button
class="filter-item"
type="primary"
icon="el-icon-refresh-left"
@click="resetFilter"
>重置</el-button
>
</div>
<div style="margin-top: 10px">
<el-button type="primary" icon="el-icon-plus" @click="handleCreate"
>新增订单</el-button
>
</div>
</el-card>
<el-card style="margin-top: 10px">
<el-table
v-loading="listLoading"
:data="orderList.results"
border
fit
stripe
highlight-current-row
max-height="600"
>
<el-table-column type="index" width="50" />
<el-table-column label="订单编号">
<template slot-scope="scope">{{ scope.row.number }}</template>
</el-table-column>
<el-table-column label="客户">
<template slot-scope="scope">{{ scope.row.customer_.name }}</template>
</el-table-column>
<el-table-column label="所属合同">
<template slot-scope="scope">{{ scope.row.contract_.name }}</template>
</el-table-column>
<el-table-column label="所需产品">
<template slot-scope="scope">{{ scope.row.product_.name }}</template>
</el-table-column>
<el-table-column label="所需数量">
<template slot-scope="scope">{{ scope.row.count }}</template>
</el-table-column>
<el-table-column label="交货日期">
<template slot-scope="scope">{{ scope.row.delivery_date }}</template>
</el-table-column>
<el-table-column label="创建时间">
<template slot-scope="scope">{{ scope.row.create_time }}</template>
</el-table-column>
<el-table-column
align="center"
label="操作"
width="220px"
>
<template slot-scope="scope">
<el-link
v-if="checkPermission(['warehouse_update'])"
@click="handleEdit(scope)"
>编辑</el-link
>
<el-link
v-if="checkPermission(['warehouse_delete'])"
type="danger"
@click="handleDelete(scope)"
>删除</el-link
>
</template>
</el-table-column>
</el-table>
<pagination
v-show="orderList.count > 0"
:total="orderList.count"
:page.sync="listQuery.page"
:limit.sync="listQuery.page_size"
@pagination="getList"
/>
</el-card>
<el-dialog
:visible.sync="dialogVisible"
:title="dialogType === 'edit' ? '编辑订单' : '新增订单'"
>
<el-form
ref="Form"
:model="order"
label-width="80px"
label-position="right"
:rules="rule1"
>
<el-form-item label="订单编号" prop="number">
<el-input v-model="order.number" placeholder="订单编号" />
</el-form-item>
<el-form-item label="所需产品" prop="product">
<el-select style="width: 100%" v-model="order.product" placeholder="请选择">
<el-option
v-for="item in productoptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="所需数量" prop="count">
<el-input type="number" v-model="order.count"></el-input>
</el-form-item>
<el-form-item label="交货日期" prop="delivery_date">
<el-date-picker
v-model="order.delivery_date"
type="date"
placeholder="选择日期"
value-format="yyyy-MM-dd"
style="width: 100%"
>
</el-date-picker>
</el-form-item>
<el-form-item label="客户" prop="customer">
<el-select style="width: 100%" v-model="order.customer" placeholder="请选择">
<el-option
v-for="item in customeroptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="所属合同" prop="contract">
<el-select style="width: 100%" v-model="order.contract" placeholder="请选择">
<el-option
v-for="item in contractoptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
</el-form>
<div style="text-align: right">
<el-button type="danger" @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="confirm('Form')">确认</el-button>
</div>
</el-dialog>
</div>
</template>
<script>
import { getOrderList, createOrder,updateOrder,deleteOrder,getContractList,getCustomerList } from "@/api/sam";
import { getMaterialList } from "@/api/mtm";
import checkPermission from "@/utils/permission";
import { genTree } from "@/utils";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
const defaulteorder = {
};
export default {
components: { Pagination },
data() {
return {
order: defaulteorder,
orderList: {
count: 0,
},
listQuery: {
page: 1,
page_size: 20,
},
contractoptions:[],
productoptions:[],
customeroptions:[],
listLoading: true,
dialogVisible: false,
dialogType: "new",
rule1: {
number: [{ required: true, message: "请输入", trigger: "blur" }],
customer: [{ required: true, message: "请输入", trigger: "blur" }],
product: [{ required: true, message: "请输入", trigger: "blur" }],
delivery_date: [{ required: true, message: "请输入", trigger: "blur" }],
},
};
},
computed: {},
watch: {},
created() {
this.getListm();
this.getListc();
this.getListcm();
this.getList();
},
methods: {
checkPermission,
getList() {
this.listLoading = true;
getOrderList(this.listQuery).then((response) => {
if (response.data) {
this.orderList = response.data;
}
this.listLoading = false;
});
},
getListm() {
getMaterialList({pageoff:true,type:1}).then((response) => {
this.productoptions = genTree(response.data);
});
},
getListc() {
getContractList({pageoff:true}).then((response) => {
this.contractoptions = genTree(response.data);
});
},
getListcm() {
getCustomerList({pageoff:true}).then((response) => {
this.customeroptions = genTree(response.data);
});
},
handleFilter() {
this.listQuery.page = 1;
this.getList();
},
resetFilter() {
this.listQuery = {
page: 1,
page_size: 20,
}
this.getList();
},
handleCreate() {
this.order = Object.assign({}, defaulteorder);
this.dialogType = "new";
this.dialogVisible = true;
this.$nextTick(() => {
this.$refs["Form"].clearValidate();
});
},
handleEdit(scope) {
this.order = Object.assign({}, scope.row); // copy obj
this.dialogType = "edit";
this.dialogVisible = true;
this.$nextTick(() => {
this.$refs["Form"].clearValidate();
});
},
handleDelete(scope) {
this.$confirm("确认删除?", "警告", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "error",
})
.then(async () => {
await deleteOrder(scope.row.id);
this.getList();
this.$message.success("成功");
})
.catch((err) => {
console.error(err);
});
},
async confirm(form) {
this.$refs[form].validate((valid) => {
if (valid) {
const isEdit = this.dialogType === "edit";
if (isEdit) {
updateOrder(this.order.id, this.order).then((res) => {
if (res.code >= 200) {
this.getList();
this.dialogVisible = false;
this.$message.success("成功");
}
});
} else {
createOrder(this.order).then((res) => {
if (res.code >= 200) {
this.getList();
this.dialogVisible = false;
this.$message.success("成功");
}
});
}
} else {
return false;
}
});
},
},
};
</script>

View File

@ -0,0 +1,37 @@
# Generated by Django 3.2.6 on 2021-09-15 01:49
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 = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('system', '0003_auto_20210812_0909'),
('em', '0006_auto_20210914_1335'),
]
operations = [
migrations.CreateModel(
name='Equipmentrecord',
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='删除标记')),
('recentlydate', models.DateField(blank=True, null=True, verbose_name='最近一次校准/检定日期')),
('nextdate', models.DateField(blank=True, null=True, verbose_name='下次应校准或检定日期')),
('description', models.CharField(blank=True, max_length=200, null=True, verbose_name='描述')),
('belong_dept', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='equipmentrecord_belong_dept', to='system.organization', verbose_name='所属部门')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='equipmentrecord_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('equipment', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='em.equipment', verbose_name='校准检定设备')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='equipmentrecord_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'abstract': False,
},
),
]

View File

@ -0,0 +1,32 @@
# Generated by Django 3.2.6 on 2021-09-16 02:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('em', '0007_equipmentrecord'),
]
operations = [
migrations.RemoveField(
model_name='equipmentrecord',
name='nextdate',
),
migrations.AddField(
model_name='equipment',
name='nextdate',
field=models.DateField(blank=True, null=True, verbose_name='下次应校准或检定日期'),
),
migrations.AddField(
model_name='equipment',
name='recentlydate',
field=models.DateField(blank=True, null=True, verbose_name='最近一次校准/检定日期'),
),
migrations.AlterField(
model_name='equipmentrecord',
name='recentlydate',
field=models.DateField(blank=True, null=True, verbose_name='校准/检定日期'),
),
]

View File

@ -0,0 +1,31 @@
# Generated by Django 3.2.6 on 2021-09-16 03:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('em', '0008_auto_20210916_1054'),
]
operations = [
migrations.RemoveField(
model_name='equipment',
name='nextdate',
),
migrations.RemoveField(
model_name='equipment',
name='recentlydate',
),
migrations.AddField(
model_name='equipmentrecord',
name='nextdate',
field=models.DateField(blank=True, null=True, verbose_name='下次应校准或检定日期'),
),
migrations.AlterField(
model_name='equipmentrecord',
name='recentlydate',
field=models.DateField(blank=True, null=True, verbose_name='最近一次校准/检定日期'),
),
]

View File

@ -75,3 +75,8 @@ class Equipment(CommonBModel):
def __str__(self): def __str__(self):
return self.number + '-' + self.name return self.number + '-' + self.name
class Equipmentrecord(CommonBModel):
equipment = models.ForeignKey(Equipment, verbose_name='校准检定设备', on_delete=models.CASCADE, null=True, blank=True)
recentlydate = models.DateField('最近一次校准/检定日期',blank=True, null=True)
nextdate = models.DateField('下次应校准或检定日期',blank=True, null=True)
description = models.CharField('描述', max_length=200, blank=True, null=True)

View File

@ -1,6 +1,6 @@
from rest_framework.serializers import ModelSerializer from rest_framework.serializers import ModelSerializer
from .models import Equipment from .models import Equipment,Equipmentrecord
from apps.system.serializers import OrganizationSimpleSerializer, UserSimpleSerializer from apps.system.serializers import OrganizationSimpleSerializer, UserSimpleSerializer
@ -20,4 +20,18 @@ class EquipmentSerializer(ModelSerializer):
class EquipmentSimpleSerializer(ModelSerializer): class EquipmentSimpleSerializer(ModelSerializer):
class Meta: class Meta:
model = Equipment model = Equipment
fields = ['id', 'number', 'name'] fields = ['id', 'number', 'name']
class EquipmentrecordSerializer(ModelSerializer):
equipment_ = EquipmentSerializer(source='equipment', read_only=True)
class Meta:
model = Equipmentrecord
fields = '__all__'
@staticmethod
def setup_eager_loading(queryset):
""" Perform necessary eager loading of data. """
queryset = queryset.select_related('equipment')
return queryset

View File

@ -1,11 +1,12 @@
from django.db.models import base from django.db.models import base
from rest_framework import urlpatterns from rest_framework import urlpatterns
from apps.em.views import EquipmentViewSet from apps.em.views import EquipmentViewSet,EquipmentrecordViewSet
from django.urls import path, include from django.urls import path, include
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
router = DefaultRouter() router = DefaultRouter()
router.register('equipment', EquipmentViewSet, basename='equipment') router.register('equipment', EquipmentViewSet, basename='equipment')
router.register('equipmentrecord', EquipmentrecordViewSet, basename='equipmentrecord')
urlpatterns = [ urlpatterns = [
path('', include(router.urls)), path('', include(router.urls)),
] ]

View File

@ -1,8 +1,10 @@
from django.shortcuts import render from django.shortcuts import render
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from apps.em.models import Equipment from rest_framework import serializers, status
from apps.em.serializers import EquipmentSerializer from rest_framework.response import Response
from apps.em.models import Equipment,Equipmentrecord
from apps.em.serializers import EquipmentSerializer,EquipmentrecordSerializer
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
@ -19,3 +21,40 @@ class EquipmentViewSet(CreateUpdateModelAMixin, OptimizationMixin, ModelViewSet)
filterset_fields = ['belong_dept', 'keeper', 'type'] filterset_fields = ['belong_dept', 'keeper', 'type']
ordering_fields = ['create_time'] ordering_fields = ['create_time']
ordering = ['-create_time'] ordering = ['-create_time']
# Create your views here.
class EquipmentrecordViewSet(CreateUpdateModelAMixin, OptimizationMixin, ModelViewSet):
"""
设备校准-增删改查
"""
perms_map = {'get': '*', 'post': 'equipmentrecord_create',
'put': 'equipmentrecord_update', 'delete': 'equipmentrecord_delete'}
queryset = Equipmentrecord.objects.all()
serializer_class = EquipmentrecordSerializer
filterset_fields = ['equipment']
ordering_fields = ['create_time']
ordering = ['-create_time']
def create(self, request, *args, **kwargs):
data = request.data
if data.get('equipment', None):
equipment = Equipment.objects.get(pk=data['equipment'])
equipment.statedm = data['state']
equipment.save()
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(status=status.HTTP_200_OK)
def update(self, request, *args, **kwargs):
data = request.data
if data.get('equipment', None):
equipment = Equipment.objects.get(pk=data['equipment'])
equipment.statedm = data['state']
equipment.save()
id = self.get_object()
serializer = self.get_serializer(id, data=data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(status=status.HTTP_200_OK)

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.6 on 2021-09-16 08:42
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mtm', '0013_auto_20210914_1049'),
]
operations = [
migrations.AlterField(
model_name='material',
name='processes',
field=models.JSONField(blank=True, default=list, null=True, verbose_name='工艺流程'),
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.6 on 2021-09-17 00:57
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mtm', '0014_alter_material_processes'),
]
operations = [
migrations.AlterField(
model_name='material',
name='name',
field=models.CharField(blank=True, max_length=100, null=True, unique=True, verbose_name='物料名称'),
),
]

View File

@ -0,0 +1,24 @@
# Generated by Django 3.2.6 on 2021-09-17 01:00
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('mtm', '0015_alter_material_name'),
]
operations = [
migrations.AlterField(
model_name='material',
name='name',
field=models.CharField(default=1, max_length=100, unique=True, verbose_name='物料名称'),
preserve_default=False,
),
migrations.AlterField(
model_name='material',
name='processes',
field=models.JSONField(blank=True, default=list, verbose_name='工艺流程'),
),
]

View File

@ -50,7 +50,7 @@ class StepSimpleSerializer(serializers.ModelSerializer):
fields = ['id', 'name', 'sort'] fields = ['id', 'name', 'sort']
class StepDetailSerializer(serializers.ModelSerializer): class StepDetailSerializer(serializers.ModelSerializer):
equipments_ = EquipmentSimpleSerializer(source='equipments', many=True)
class Meta: class Meta:
model = Step model = Step
fields = '__all__' fields = '__all__'

View File

View File

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

View File

@ -0,0 +1,6 @@
from django.apps import AppConfig
class QmConfig(AppConfig):
name = 'apps.qm'
verbose_name = '质量管理'

View File

@ -0,0 +1,73 @@
# Generated by Django 3.2.6 on 2021-09-15 14:06
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),
('system', '0003_auto_20210812_0909'),
]
operations = [
migrations.CreateModel(
name='Standard',
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='标准编号')),
('name', models.CharField(max_length=100, verbose_name='标准名称')),
('enabled', models.BooleanField(default=True, verbose_name='是否启用')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='standard_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('file', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, to='system.file', verbose_name='文件')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='standard_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'verbose_name': '标准库',
'verbose_name_plural': '标准库',
},
),
migrations.CreateModel(
name='TestItem',
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='名称')),
('term_number', models.CharField(max_length=100, verbose_name='条款号')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='testitem_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('standard', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='qm.standard', verbose_name='关联标准')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='testitem_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'verbose_name': '检验项目',
'verbose_name_plural': '检验项目',
},
),
migrations.CreateModel(
name='AnalysisItem',
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='名称')),
('rules', models.JSONField(default=dict, verbose_name='判定规则')),
('create_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='analysisitem_create_by', to=settings.AUTH_USER_MODEL, verbose_name='创建人')),
('testitem', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='qm.testitem', verbose_name='关联检验项目')),
('update_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='analysisitem_update_by', to=settings.AUTH_USER_MODEL, verbose_name='最后编辑人')),
],
options={
'verbose_name': '检验分析项',
},
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 3.2.6 on 2021-09-16 02:54
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('qm', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='analysisitem',
name='rules',
field=models.JSONField(default=list, verbose_name='判定规则'),
),
]

View File

View File

@ -0,0 +1,41 @@
from django.db import models
from apps.system.models import CommonAModel, File
# Create your models here.
class Standard(CommonAModel):
"""
标准
"""
number = models.CharField('标准编号', max_length=100)
name = models.CharField('标准名称', max_length=100)
enabled = models.BooleanField('是否启用', default=True)
file = models.ForeignKey(File, verbose_name='文件', null=True, blank=True, on_delete=models.CASCADE)
class Meta:
verbose_name = '标准库'
verbose_name_plural = verbose_name
def __str__(self):
return self.number + '-' + self.name
class TestItem(CommonAModel):
"""
检验项目
"""
name = models.CharField('名称', max_length=100)
standard = models.ForeignKey(Standard, verbose_name='关联标准', on_delete=models.CASCADE)
term_number = models.CharField('条款号', max_length=100)
class Meta:
verbose_name = '检验项目'
verbose_name_plural = verbose_name
class AnalysisItem(CommonAModel):
"""
检验分析项
"""
name = models.CharField('名称', max_length=100)
testitem = models.ForeignKey(TestItem, on_delete=models.CASCADE, verbose_name='关联检验项目')
rules =models.JSONField('判定规则', default=list)
class Meta:
verbose_name = '检验分析项'

View File

@ -0,0 +1,33 @@
from rest_framework import serializers
from apps.system.serializers import FileSimpleSerializer
from .models import Standard, TestItem
class StandardCreateUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = Standard
fields = ['name', 'file', 'enabled', 'number']
class StandardSerializer(serializers.ModelSerializer):
file_ = FileSimpleSerializer(source='file', read_only=True)
class Meta:
model = Standard
fields = '__all__'
class StandardSimpleSerializer(serializers.ModelSerializer):
class Meta:
model = Standard
fields = ['id', 'name', 'number']
class TestItemCreateUpdateSerializer(serializers.ModelSerializer):
class Meta:
model = TestItem
fields = ['name', 'standard', 'term_number']
class TestItemSerializer(serializers.ModelSerializer):
standard_ = StandardSimpleSerializer(source='standard', read_only=True)
class Meta:
model = TestItem
fields = '__all__'
class AnalysisItemSerializer(serializers.ModelSerializer):
pass

View File

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

13
hb_server/apps/qm/urls.py Normal file
View File

@ -0,0 +1,13 @@
from apps.qm.views import StandardViewSet, TestItemViewSet
from django.db.models import base
from rest_framework import urlpatterns
from django.urls import path, include
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register('standard', StandardViewSet, basename='standard')
router.register('testitem', TestItemViewSet, basename='testitem')
urlpatterns = [
path('', include(router.urls)),
]

View File

@ -0,0 +1,39 @@
from apps.qm.serializers import StandardCreateUpdateSerializer, StandardSerializer, TestItemCreateUpdateSerializer, TestItemSerializer
from apps.qm.models import Standard, TestItem
from django.shortcuts import render
from rest_framework.viewsets import ModelViewSet
from apps.system.mixins import CreateUpdateModelAMixin
# Create your views here.
class StandardViewSet(CreateUpdateModelAMixin, ModelViewSet):
"""
标准规范-增删改查
"""
perms_map = {'*': '*'}
queryset = Standard.objects.select_related('file').all()
serializer_class = StandardSerializer
search_fields = ['name', 'number']
filterset_fields = []
ordering_fields = ['number']
ordering = ['id']
def get_serializer_class(self):
if self.action in ['create', 'update']:
return StandardCreateUpdateSerializer
return StandardSerializer
class TestItemViewSet(CreateUpdateModelAMixin, ModelViewSet):
"""
检验项目增删改查
"""
perms_map = {'*': '*'}
queryset = TestItem.objects.select_related('standard').all()
serializer_class = TestItemSerializer
search_fields = ['name', 'standard__name', 'standard__number']
filterset_fields = ['standard']
ordering_fields = ['id']
ordering = ['id']
def get_serializer_class(self):
if self.action in ['create', 'update']:
return TestItemCreateUpdateSerializer
return TestItemSerializer

View File

@ -2,6 +2,8 @@ from rest_framework import serializers
from .models import Contract, Customer, Order from .models import Contract, Customer, Order
from apps.mtm.serializers import MaterialSimpleSerializer
class CustomerSerializer(serializers.ModelSerializer): class CustomerSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Customer model = Customer
@ -14,10 +16,11 @@ class CustomerCreateUpdateSerializer(serializers.ModelSerializer):
class CustomerSimpleSerializer(serializers.ModelSerializer): class CustomerSimpleSerializer(serializers.ModelSerializer):
class Meta: class Meta:
model = Customer
fields = ['id', 'name'] fields = ['id', 'name']
class ContractSerializer(serializers.ModelSerializer): class ContractSerializer(serializers.ModelSerializer):
customer_ = CustomerSimpleSerializer(source='customer', read_only=True)
class Meta: class Meta:
model = Contract model = Contract
fields = '__all__' fields = '__all__'
@ -41,6 +44,7 @@ class OrderCreateUpdateSerializer(serializers.ModelSerializer):
class OrderSerializer(serializers.ModelSerializer): class OrderSerializer(serializers.ModelSerializer):
contract_ = ContractSimpleSerializer(source='contract', read_only=True) contract_ = ContractSimpleSerializer(source='contract', read_only=True)
customer_ = CustomerSimpleSerializer(source='customer', read_only=True) customer_ = CustomerSimpleSerializer(source='customer', read_only=True)
product_ = MaterialSimpleSerializer(source='product', read_only=True)
class Meta: class Meta:
model = Order model = Order
fields = '__all__' fields = '__all__'

View File

@ -1,12 +1,13 @@
from django.db.models import base from django.db.models import base
from rest_framework import urlpatterns from rest_framework import urlpatterns
from apps.sam.views import CustomerViewSet,ContractViewSet from apps.sam.views import CustomerViewSet,ContractViewSet,OrderViewSet
from django.urls import path, include from django.urls import path, include
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
router = DefaultRouter() router = DefaultRouter()
router.register('customer', CustomerViewSet, basename='customer') router.register('customer', CustomerViewSet, basename='customer')
router.register('contract', ContractViewSet, basename='contract') router.register('contract', ContractViewSet, basename='contract')
router.register('order', OrderViewSet, basename='order')
urlpatterns = [ urlpatterns = [
path('', include(router.urls)), path('', include(router.urls)),

View File

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

View File

@ -66,6 +66,8 @@ urlpatterns = [
path('api/mtm/', include('apps.mtm.urls')), path('api/mtm/', include('apps.mtm.urls')),
path('api/inm/', include('apps.inm.urls')), path('api/inm/', include('apps.inm.urls')),
path('api/sam/', include('apps.sam.urls')), path('api/sam/', include('apps.sam.urls')),
path('api/qm/', include('apps.qm.urls')),
# 工具 # 工具
path('api/utils/signature/', GenSignature.as_view()), path('api/utils/signature/', GenSignature.as_view()),