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

This commit is contained in:
shijing 2021-10-25 15:17:54 +08:00
commit 46e1547571
25 changed files with 783 additions and 86 deletions

View File

@ -55,3 +55,20 @@ export function updatesubproductionplan(id, data) {
data data
}) })
} }
//子计划详情
export function getProgress(id) {
return request({
url: `/pm/subproduction_plan/${id}/progress/`,
method: 'get'
})
}
//子计划下达
export function issuesubplan(id) {
return request({
url: `/pm/subproduction_plan/${id}/issue/`,
method: 'post',
})
}

View File

@ -176,6 +176,28 @@ export const asyncRoutes = [
meta: { title: '生产作业管理', icon: 'example', perms: ['pm_testitem'] } meta: { title: '生产作业管理', icon: 'example', perms: ['pm_testitem'] }
} }
] ]
}
,
{
path: '/wpm',
component: Layout,
redirect: '/wpm/worktask',
name: 'pm',
meta: { title: '车间生产', icon: 'example', perms: ['equipment_set'] },
children: [
{
path: 'worktask',
name: 'worktask',
component: () => import('@/views/wpm/worktask'),
meta: { title: '车间任务', icon: 'example', perms: ['index_manage'] }
},
{
path: 'testitem',
name: 'testitem',
component: () => import('@/views/wpm/testitem'),
meta: { title: '检测项目', icon: 'example', perms: ['index_manage'] }
}
]
}, },
{ {
path: '/em', path: '/em',

View File

@ -10,6 +10,7 @@ body {
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif; font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
background-color: #e9e9e9;
} }
label { label {

View File

@ -44,10 +44,31 @@
> >
<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.number }}</template> <template slot-scope="scope">
{{ scope.row.number }}
</template>
</el-table-column> </el-table-column>
<el-table-column label="物料类别" :filters="[{ text: '成品', value: 1 }, { text: '半成品', value: 2 },{ text: '主要原料', value: 3 }, { text: '辅助原料', value: 4 }]" <el-table-column label="物料类别" :filters="[{
value: 1,
text: '成品'
}, {
value: 2,
text: '半成品'
}, {
value: 3,
text: '主要原料'
}, {
value: 4,
text: '辅助原料'
}, {
value: 5,
text: '加工工具'
}, {
value: 6,
text: '辅助工具'
}]"
:filter-method="filterTag" :filter-method="filterTag"
filter-placement="bottom-end"> filter-placement="bottom-end">
<template slot-scope="scope"> {{options_[scope.row.type]}}</template> <template slot-scope="scope"> {{options_[scope.row.type]}}</template>

View File

@ -158,23 +158,39 @@
v-el-height-adaptive-table="{bottomOffset: 50}" 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="字段名称">
<template slot-scope="scope">{{ scope.row.field_name }}</template>
</el-table-column>
<el-table-column label="字段类型"> <el-table-column label="字段类型">
<template slot-scope="scope">{{ options_[scope.row.field_type] }}</template> <template slot-scope="scope">{{ options_[scope.row.field_type] }}</template>
</el-table-column> </el-table-column>
<el-table-column label="字段名称">
<template slot-scope="scope">{{ scope.row.field_name }}</template>
</el-table-column>
<el-table-column label="字段标识"> <el-table-column label="字段标识">
<template slot-scope="scope">{{ scope.row.field_key }}</template> <template slot-scope="scope">{{ scope.row.field_key }}</template>
</el-table-column> </el-table-column>
<el-table-column label="上限值">
<el-table-column label="选项显示名"> <template slot-scope="scope">{{ scope.row.high_limit }}</template>
<template slot-scope="scope">{{ scope.row.field_choice }}</template>
</el-table-column> </el-table-column>
<el-table-column label="上限规则">
<template slot-scope="scope">{{ highoptionss_[scope.row.high_rule] }}</template>
</el-table-column>
<el-table-column label="下限值">
<template slot-scope="scope">{{ scope.row.low_limit }}</template>
</el-table-column>
<el-table-column label="下限规则">
<template slot-scope="scope"> {{ lowoptionss_[scope.row.low_rule] }}</template>
</el-table-column>
<el-table-column label="是否判定">
<template slot-scope="scope">
<el-tag v-if="scope.row.need_judge==true"></el-tag>
<el-tag v-else></el-tag>
</template>
</el-table-column>
<el-table-column <el-table-column
@ -200,7 +216,7 @@
</el-table> </el-table>
<el-dialog :visible.sync="dialogVisible1" :title="dialogType1 === 'edit' ? '编辑表格字段' : '新增表格字段'"> <el-dialog :visible.sync="dialogVisible1" :title="dialogType1 === 'edit' ? '编辑表格字段' : '新增表格字段'">
<el-form ref="Form" :model="field" label-width="80px" label-position="right"> <el-form ref="Form" :model="field" label-width="100px" label-position="right">
<el-form-item label="字段类型" prop="field_type"> <el-form-item label="字段类型" prop="field_type">
<el-select style="width: 100%" v-model="field.field_type" placeholder="请选择"> <el-select style="width: 100%" v-model="field.field_type" placeholder="请选择">
<el-option <el-option
@ -231,6 +247,36 @@
</el-col> </el-col>
</el-row> </el-row>
</el-form-item> </el-form-item>
<el-form-item label="是否需要判定" prop="need_judge">
<el-switch v-model="field.need_judge"></el-switch>
</el-form-item>
<el-form-item label="上限值" prop="high_limit">
<el-input-number v-model="field.high_limit" :precision="2" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="上限规则" prop="high_rule">
<el-select style="width: 100%" v-model="field.high_rule" placeholder="请选择">
<el-option
v-for="item in highoptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="下限值" prop="low_limit">
<el-input-number v-model="field.low_limit" :precision="2" :min="0"></el-input-number>
</el-form-item>
<el-form-item label="下限规则" prop="low_rule">
<el-select style="width: 100%" v-model="field.low_rule" placeholder="请选择">
<el-option
v-for="item in lowoptions"
:key="item.value"
:label="item.label"
:value="item.value">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="排序" prop="sort"> <el-form-item label="排序" prop="sort">
<el-input-number v-model="field.sort" :min="1" placeholder="排序"></el-input-number> <el-input-number v-model="field.sort" :min="1" placeholder="排序"></el-input-number>
</el-form-item> </el-form-item>
@ -266,7 +312,7 @@
}; };
const defaultfield = { const defaultfield = {
}; };
export default { export default {
components: { Pagination,vueJsonEditor }, components: { Pagination,vueJsonEditor },
@ -278,6 +324,7 @@
upUrl: upUrl(), upUrl: upUrl(),
fileList:[], fileList:[],
listLoading: true, listLoading: true,
need_judge:false,
dialogVisibles: false, dialogVisibles: false,
dialogVisibleForm: false, dialogVisibleForm: false,
dialogTypes: "new", dialogTypes: "new",
@ -317,6 +364,20 @@
page: 1, page: 1,
page_size: 20, page_size: 20,
}, },
highoptions:[{ value: 1,
label: '<'},{ value: 2,
label: '<='}],
lowoptions:[{ value: 1,
label: '>'},{ value: 2,
label: '>='}],
highoptionss_:{
1: '<',
2: '<='
},
lowoptionss_:{
1: '>',
2: '>='
},
options_: { options_: {
'string':'文本', 'string':'文本',
'int':'整数', 'int':'整数',

View File

@ -283,6 +283,12 @@
<el-table-column label="单位消耗量"> <el-table-column label="单位消耗量">
<template slot-scope="scope">{{ scope.row.count }}</template> <template slot-scope="scope">{{ scope.row.count }}</template>
</el-table-column> </el-table-column>
<el-table-column label="是否主产出">
<template slot-scope="scope">
<el-tag v-if="scope.row.is_main==true"> </el-tag>
<el-tag v-else></el-tag>
</template>
</el-table-column>
@ -315,7 +321,7 @@
<el-form <el-form
ref="Forms" ref="Forms"
:model="outputmaterial" :model="outputmaterial"
label-width="80px" label-width="120px"
label-position="right" label-position="right"
> >
@ -334,6 +340,10 @@
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item label="是否主产出" prop="is_main">
<el-switch v-model="outputmaterial.is_main"></el-switch>
</el-form-item>
<el-form-item label="排序" prop="sort"> <el-form-item label="排序" prop="sort">
<el-input-number <el-input-number
v-model="outputmaterial.sort" v-model="outputmaterial.sort"
@ -558,6 +568,7 @@ export default {
inputtableData:"", inputtableData:"",
editorOption: {} , editorOption: {} ,
processOptions:[], processOptions:[],
is_main:false,
techdoc: defaulttechdoc, techdoc: defaulttechdoc,
subproducation:defaultsubproducation, subproducation:defaultsubproducation,
inputmaterial: defaultinputmaterial, inputmaterial: defaultinputmaterial,

View File

@ -12,7 +12,7 @@
fit fit
stripe stripe
style="width: 100%" style="width: 100%"
max-height="400" height="300"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
@ -51,6 +51,7 @@
<el-table-column label="交付截止时间"> <el-table-column label="交付截止时间">
<template slot-scope="scope">{{ scope.row.order_.delivery_date }}</template> <template slot-scope="scope">{{ scope.row.order_.delivery_date }}</template>
</el-table-column> </el-table-column>
<el-table-column label="是否生成子计划"> <el-table-column label="是否生成子计划">
<template slot-scope="scope" > <template slot-scope="scope" >
<el-tag v-if="scope.row.is_planed==false"></el-tag> <el-tag v-if="scope.row.is_planed==false"></el-tag>
@ -73,7 +74,7 @@
<el-link type="primary" <el-link type="primary"
v-else v-else
@click="handleWork(scope)" @click="handleWork(scope)"
>子计划</el-link> >子计划</el-link>
</template> </template>
</el-table-column> </el-table-column>
</el-table> </el-table>
@ -95,6 +96,7 @@
fit fit
stripe stripe
style="width: 100%" style="width: 100%"
height="250"
> >
<el-table-column type="index" width="50" /> <el-table-column type="index" width="50" />
@ -125,6 +127,7 @@
<template slot-scope="scope">{{ scope.row.delivery_date }}</template> <template slot-scope="scope">{{ scope.row.delivery_date }}</template>
</el-table-column> </el-table-column>
<el-table-column label="创建时间"> <el-table-column label="创建时间">
<template slot-scope="scope">{{ scope.row.create_time }}</template> <template slot-scope="scope">{{ scope.row.create_time }}</template>
@ -235,6 +238,7 @@ export default {
number: [{ required: true, message: "请输入", trigger: "blur" }], number: [{ required: true, message: "请输入", trigger: "blur" }],
}, },
}; };
}, },
computed: {}, computed: {},
@ -301,6 +305,8 @@ export default {
await createsubplan(scope.row.id).then((res) => { await createsubplan(scope.row.id).then((res) => {
if (res.code >= 200) { if (res.code >= 200) {
this.$message.success("生成子计划成功!"); this.$message.success("生成子计划成功!");
this.$router.push({name: "work", params: { id: scope.row.id }, })
this.getplanList()
} }
}); });
}) })

View File

@ -12,6 +12,7 @@
<el-table <el-table
:data="orderList.results" :data="orderList.results"
border border
ref="multipleTable"
fit fit
stripe stripe
style="width: 100%" style="width: 100%"
@ -233,7 +234,7 @@ export default {
this.listLoading = false; this.listLoading = false;
}); });
}, },
handleSelectionChange(row) { handleSelectionChange(rows) {
let _this=this let _this=this
_this.mutipID=[] _this.mutipID=[]
row.forEach((item) => { row.forEach((item) => {
@ -243,12 +244,20 @@ export default {
}); });
}); });
setTimeout(() => {
rows.forEach(row => {
this.$refs.multipleTable.toggleRowSelection(row);
});
}, 1)
}, },
//物料计算 //物料计算
handlecount() handlecount()
{ {
createresource(this.mutipID).then((res) => { createresource(this.mutipID).then((res) => {
if (res.code >= 200) { if (res.code >= 200) {
this.materialpzTable=res.data; this.materialpzTable=res.data;

View File

@ -26,6 +26,16 @@
</el-table-column> </el-table-column>
<el-table-column label="工序编号"> <el-table-column label="工序编号">
<template slot-scope="scope">{{ scope.row.process_.number }}</template> <template slot-scope="scope">{{ scope.row.process_.number }}</template>
</el-table-column>
<el-table-column label="子工序">
<template slot-scope="scope" v-if="scope.row.steps">
<el-tag v-for="item in scope.row.steps"
:key="item.number"
:label="item.name"
:value="item.number">{{item.name}}</el-tag>
</template>
</el-table-column> </el-table-column>
<el-table-column label="开工时间"> <el-table-column label="开工时间">
<template slot-scope="scope">{{ scope.row.start_date }}</template> <template slot-scope="scope">{{ scope.row.start_date }}</template>
@ -33,7 +43,9 @@
<el-table-column label="完工时间"> <el-table-column label="完工时间">
<template slot-scope="scope">{{ scope.row.end_date }}</template> <template slot-scope="scope">{{ scope.row.end_date }}</template>
</el-table-column> </el-table-column>
<el-table-column label="下达状态">
<template slot-scope="scope">{{ state_[scope.row.state] }}</template>
</el-table-column>
<el-table-column label="创建时间"> <el-table-column label="创建时间">
<template slot-scope="scope">{{ scope.row.create_time }}</template> <template slot-scope="scope">{{ scope.row.create_time }}</template>
</el-table-column> </el-table-column>
@ -43,11 +55,21 @@
width="100px" width="100px"
> >
<template slot-scope="scope"> <template slot-scope="scope">
<el-link type="primary" <el-link type="primary"
v-if="checkPermission(['warehouse_update'])" v-if="checkPermission(['warehouse_update'])"
@click="handleclick(scope)" @click="handleclick(scope)"
>编辑</el-link >修改日期</el-link
>
<el-link type="primary"
v-if="scope.row.state==0"
@click="handleissuedclick(scope)"
>下达</el-link
>
<el-link type="primary"
v-if="checkPermission(['warehouse_update'])"
@click="handleselectclick(scope)"
>查看详情</el-link
> >
</template> </template>
@ -99,10 +121,55 @@
<el-button type="primary" @click="confirm('Form')">确认</el-button> <el-button type="primary" @click="confirm('Form')">确认</el-button>
</div> </div>
</el-dialog> </el-dialog>
<el-dialog
:visible.sync="dialogVisibles"
>
<el-table
:data="progressList"
border
fit
stripe
style="width: 100%"
max-height="400"
>
<el-table-column type="index" width="50" />
<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.count_real }}</template>
</el-table-column>
<el-table-column label="生产计划编号">
<template slot-scope="scope">{{ scope.row.subproduction_plan }}</template>
</el-table-column>
<el-table-column label="物料名称">
<template slot-scope="scope">{{ scope.row.material_.name }}</template>
</el-table-column>
<el-table-column label="物料编号">
<template slot-scope="scope">{{ scope.row.material_.number }}</template>
</el-table-column>
<el-table-column label="物料型号">
<template slot-scope="scope">{{ scope.row.material_.specification }}</template>
</el-table-column>
<el-table-column label="物料单位">
<template slot-scope="scope">{{ scope.row.material_.unit }}</template>
</el-table-column>
</el-table>
<div style="text-align: right">
<el-button type="danger" @click="dialogVisibles = false">取消</el-button>
</div>
</el-dialog>
</div> </div>
</template> </template>
<script> <script>
import { getsubproductionplanList,updatesubproductionplan } from "@/api/pm"; import { getsubproductionplanList,updatesubproductionplan,getProgress,issuesubplan } from "@/api/pm";
import checkPermission from "@/utils/permission"; import checkPermission from "@/utils/permission";
@ -123,14 +190,21 @@ export default {
page_size: 20, page_size: 20,
}, },
progressList:[],
listLoading: true, listLoading: true,
dialogVisible: false, dialogVisible: false,
dialogVisibles: false,
dialogType: "new", dialogType: "new",
rule1: { rule1: {
number: [{ required: true, message: "请输入", trigger: "blur" }], number: [{ required: true, message: "请输入", trigger: "blur" }],
}, },
state_:{
0:'制定中',
1:'已下达',
2:'已接受',
3:'生产中',
4:'已完成'}
}; };
}, },
computed: {}, computed: {},
@ -163,6 +237,16 @@ export default {
}); });
}, },
handleselectclick(scope)
{
this.dialogVisibles = true;
getProgress(scope.row.id).then((res) => {
if (res.code >= 200) {
this.progressList = res.data;
}
});
},
confirm() confirm()
{ {
updatesubproductionplan(this.subproductionplan.id,this.subproductionplan).then((res) => { updatesubproductionplan(this.subproductionplan.id,this.subproductionplan).then((res) => {
@ -172,9 +256,27 @@ export default {
this.$message.success("成功"); this.$message.success("成功");
} }
}); });
} },
handleissuedclick(scope)
{
this.$confirm("确定下达子计划?", "提醒", {
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "error",
})
.then(async () => {
await issuesubplan(scope.row.id).then((res) => {
if (res.code >= 200) {
this.getspList();
this.$message.success("子计划已下达!");
}
});
})
.catch((err) => {
console.error(err);
});
}
}, },
}; };

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

@ -0,0 +1,107 @@
<template>
<div class="app-container">
<el-card class="box-card">
<div slot="header" class="clearfix">
<span>生产任务列表</span>
</div>
<el-table
:data="subproductionplanList.results"
border
fit
stripe
style="width: 100%"
max-height="400"
>
<el-table-column type="index" width="50" />
<el-table-column label="生产子计划名">
<template slot-scope="scope">{{ scope.row.workshop_.name }}</template>
</el-table-column>
<el-table-column label="工序名">
<template slot-scope="scope">{{ scope.row.process_.name }}</template>
</el-table-column>
<el-table-column label="工序编号">
<template slot-scope="scope">{{ scope.row.process_.number }}</template>
</el-table-column>
<el-table-column label="子工序">
<template slot-scope="scope" v-if="scope.row.steps">
<el-tag v-for="item in scope.row.steps"
:key="item.number"
:label="item.name"
:value="item.number">{{item.name}}</el-tag>
</template>
</el-table-column>
<el-table-column label="开工时间">
<template slot-scope="scope">{{ scope.row.start_date }}</template>
</el-table-column>
<el-table-column label="完工时间">
<template slot-scope="scope">{{ scope.row.end_date }}</template>
</el-table-column>
<el-table-column label="创建时间">
<template slot-scope="scope">{{ scope.row.create_time }}</template>
</el-table-column>
</el-table>
<pagination
v-show="subproductionplanList.count > 0"
:total="subproductionplanList.count"
:page.sync="listQuery.page"
:limit.sync="listQuery.page_size"
@pagination="getspList"
/>
</el-card>
</div>
</template>
<script>
import { getsubproductionplanList } from "@/api/pm";
import checkPermission from "@/utils/permission";
import Pagination from "@/components/Pagination"; // secondary package based on el-pagination
export default {
components: { Pagination },
data() {
return {
subproductionplanList: {
count: 0,
},
listQuery: {
page: 1,
page_size: 20,
},
listLoading: true
};
},
computed: {},
watch: {},
created() {
this.getspList();
},
methods: {
checkPermission,
//订单列表
getspList() {
this.listLoading = true;
console.log(this.listQuery)
getsubproductionplanList(this.listQuery).then((response) => {
if (response.data) {
this.subproductionplanList = response.data;
}
this.listLoading = false;
});
},
},
};
</script>

View File

@ -47,6 +47,8 @@ class MaterialBatch(BaseModel):
verbose_name = '库存表' verbose_name = '库存表'
verbose_name_plural = verbose_name verbose_name_plural = verbose_name
class FIFO(CommonAModel): class FIFO(CommonAModel):
""" """
出入库记录 出入库记录
@ -66,4 +68,14 @@ class FIFO(CommonAModel):
# 领料详细记录 # 领料详细记录
# """ # """
class Product(CommonAModel):
"""
具体产品
"""
number = models.CharField('物品编号', unique=True, null=True, blank=True, max_length=50)
material = models.ForeignKey(Material, verbose_name='物料类型', on_delete=models.CASCADE)
warehouse = models.ForeignKey(WareHouse, on_delete=models.CASCADE, verbose_name='所在仓库')
batch = models.CharField('所属批次号', max_length=100, null=True, blank=True)
fifos = models.JSONField('关联出入库记录', default=list, blank=True)

View File

@ -46,6 +46,8 @@ class SubProductionPlan(CommonAModel):
process = models.ForeignKey(Process, verbose_name='关联大工序', on_delete=models.CASCADE) process = models.ForeignKey(Process, verbose_name='关联大工序', on_delete=models.CASCADE)
steps = models.JSONField('工艺步骤', default=list) steps = models.JSONField('工艺步骤', default=list)
state = models.IntegerField('状态', default=0) state = models.IntegerField('状态', default=0)
start_date_real = models.DateField('实际开工日期', null=True, blank=True)
end_date_real = models.DateField('实际完工日期', null=True, blank=True)
class Meta: class Meta:
verbose_name = '子生产计划' verbose_name = '子生产计划'
verbose_name_plural = verbose_name verbose_name_plural = verbose_name

View File

@ -1,3 +1,4 @@
from datetime import timezone
from rest_framework import serializers from rest_framework import serializers
from rest_framework.views import APIView from rest_framework.views import APIView
from apps.em.models import Equipment from apps.em.models import Equipment
@ -122,6 +123,19 @@ class SubProductionPlanViewSet(CreateUpdateModelAMixin, ListModelMixin, UpdateMo
obj.save() obj.save()
return Response() return Response()
raise APIException('计划状态有误') raise APIException('计划状态有误')
@action(methods=['post'], detail=True, perms_map={'post':'*'}, serializer_class=serializers.Serializer)
def start(self, request, pk=None):
"""
开始生产
"""
obj = self.get_object()
if obj.state in [1,2]:
obj.state = 3
obj.start_date_real = timezone.now()
obj.save()
return Response()
raise APIException('计划状态有误')
class ResourceViewSet(GenericViewSet): class ResourceViewSet(GenericViewSet):

View File

@ -18,7 +18,7 @@ class TicketFilterSet(filters.FilterSet):
elif value == 'worked': elif value == 'worked':
queryset = queryset.filter(ticketflow_ticket__participant=user).exclude(create_by=user).order_by('-update_time').distinct() queryset = queryset.filter(ticketflow_ticket__participant=user).exclude(create_by=user).order_by('-update_time').distinct()
elif value == 'cc': elif value == 'cc':
pass queryset = queryset.filter(ticketflow_ticket__participant_cc__contains=user.id).exclude(create_by=user).order_by('-update_time').distinct()
elif value == 'all': elif value == 'all':
pass pass
else: else:

View File

@ -0,0 +1,53 @@
# Generated by Django 3.2.6 on 2021-10-24 15:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wf', '0015_auto_20211021_1049'),
]
operations = [
migrations.AddField(
model_name='state',
name='participant_cc',
field=models.JSONField(blank=True, default=list, help_text='抄送给(userid列表)', verbose_name='抄送给'),
),
migrations.AddField(
model_name='ticketflow',
name='participant_cc',
field=models.JSONField(blank=True, default=list, help_text='抄送给(userid列表)', verbose_name='抄送给'),
),
migrations.AddField(
model_name='wfscript',
name='func_str',
field=models.CharField(blank=True, max_length=50, null=True, verbose_name='函数名'),
),
migrations.AlterField(
model_name='state',
name='participant_type',
field=models.IntegerField(blank=True, choices=[(0, '无处理人'), (1, '个人'), (2, '多人'), (4, '角色'), (6, '脚本'), (7, '工单的字段'), (9, '代码获取')], default=1, help_text='0.无处理人,1.个人,2.多人,3.部门,4.角色,5.变量(支持工单创建人,创建人的leader),6.脚本,7.工单的字段内容(如表单中的"测试负责人",需要为用户名或者逗号隔开的多个用户名),8.父工单的字段内容。 初始状态请选择类型5参与人填create_by', verbose_name='参与者类型'),
),
migrations.AlterField(
model_name='ticket',
name='participant_type',
field=models.IntegerField(choices=[(0, '无处理人'), (1, '个人'), (2, '多人'), (4, '角色'), (6, '脚本'), (7, '工单的字段'), (9, '代码获取')], default=0, help_text='0.无处理人,1.个人,2.多人', verbose_name='当前处理人类型'),
),
migrations.AlterField(
model_name='ticketflow',
name='intervene_type',
field=models.IntegerField(choices=[(0, '正常处理'), (1, '转交'), (2, '加签'), (3, '加签处理完成'), (4, '接单'), (5, '评论'), (6, '删除'), (7, '强制关闭'), (8, '强制修改状态'), (9, 'hook操作'), (10, '撤回'), (11, '抄送')], default=0, help_text='流转类型', verbose_name='干预类型'),
),
migrations.AlterField(
model_name='ticketflow',
name='participant_type',
field=models.IntegerField(choices=[(0, '无处理人'), (1, '个人'), (2, '多人'), (4, '角色'), (6, '脚本'), (7, '工单的字段'), (9, '代码获取')], default=0, help_text='0.无处理人,1.个人,2.多人', verbose_name='处理人类型'),
),
migrations.AlterField(
model_name='wfscript',
name='usage',
field=models.IntegerField(choices=[(1, '获取处理人'), (2, '执行操作')], default=2, verbose_name='脚本用途'),
),
]

View File

@ -85,6 +85,7 @@ class State(CommonAModel):
state_fields = models.JSONField('表单字段', default=dict, help_text='json格式字典存储,包括读写属性1只读2必填3可选. 示例:{"create_time":1,"title":2, "sn":1}, 内置特殊字段participant_info.participant_name:当前处理人信息(部门名称、角色名称)state.state_name:当前状态的状态名,workflow.workflow_name:工作流名称') # json格式存储,包括读写属性1只读2必填3可选4不显示, 字典的字典 state_fields = models.JSONField('表单字段', default=dict, help_text='json格式字典存储,包括读写属性1只读2必填3可选. 示例:{"create_time":1,"title":2, "sn":1}, 内置特殊字段participant_info.participant_name:当前处理人信息(部门名称、角色名称)state.state_name:当前状态的状态名,workflow.workflow_name:工作流名称') # json格式存储,包括读写属性1只读2必填3可选4不显示, 字典的字典
distribute_type = models.IntegerField('分配方式', default=1, choices=state_distribute_choices, help_text='1.主动接单(如果当前处理人实际为多人的时候,需要先接单才能处理) 2.直接处理(即使当前处理人实际为多人,也可以直接处理) 3.随机分配(如果实际为多人,则系统会随机分配给其中一个人) 4.全部处理(要求所有参与人都要处理一遍,才能进入下一步)') distribute_type = models.IntegerField('分配方式', default=1, choices=state_distribute_choices, help_text='1.主动接单(如果当前处理人实际为多人的时候,需要先接单才能处理) 2.直接处理(即使当前处理人实际为多人,也可以直接处理) 3.随机分配(如果实际为多人,则系统会随机分配给其中一个人) 4.全部处理(要求所有参与人都要处理一遍,才能进入下一步)')
filter_policy = models.IntegerField('参与人过滤策略', default=0, choices=state_filter_choices) filter_policy = models.IntegerField('参与人过滤策略', default=0, choices=state_filter_choices)
participant_cc = models.JSONField('抄送给', default=list, blank=True, help_text='抄送给(userid列表)')
class Transition(CommonAModel): class Transition(CommonAModel):
""" """
@ -108,6 +109,7 @@ class Transition(CommonAModel):
TRANSITION_INTERVENE_TYPE_ALTER_STATE = 8 # 强制修改状态操作 TRANSITION_INTERVENE_TYPE_ALTER_STATE = 8 # 强制修改状态操作
TRANSITION_INTERVENE_TYPE_HOOK = 9 # hook操作 TRANSITION_INTERVENE_TYPE_HOOK = 9 # hook操作
TRANSITION_INTERVENE_TYPE_RETREAT = 10 # 撤回 TRANSITION_INTERVENE_TYPE_RETREAT = 10 # 撤回
TRANSITION_INTERVENE_TYPE_CC = 11 # 抄送
intervene_type_choices = ( intervene_type_choices = (
(0, '正常处理'), (0, '正常处理'),
@ -120,7 +122,8 @@ class Transition(CommonAModel):
(TRANSITION_INTERVENE_TYPE_CLOSE, '强制关闭'), (TRANSITION_INTERVENE_TYPE_CLOSE, '强制关闭'),
(TRANSITION_INTERVENE_TYPE_ALTER_STATE, '强制修改状态'), (TRANSITION_INTERVENE_TYPE_ALTER_STATE, '强制修改状态'),
(TRANSITION_INTERVENE_TYPE_HOOK, 'hook操作'), (TRANSITION_INTERVENE_TYPE_HOOK, 'hook操作'),
(TRANSITION_INTERVENE_TYPE_RETREAT, '撤回') (TRANSITION_INTERVENE_TYPE_RETREAT, '撤回'),
(TRANSITION_INTERVENE_TYPE_CC, '抄送')
) )
name = models.CharField('操作', max_length=50) name = models.CharField('操作', max_length=50)
@ -219,6 +222,7 @@ class TicketFlow(BaseModel):
state = models.ForeignKey(State, verbose_name='当前状态', default=0, blank=True, on_delete=models.CASCADE) state = models.ForeignKey(State, verbose_name='当前状态', default=0, blank=True, on_delete=models.CASCADE)
ticket_data = models.JSONField('工单数据', default=dict, blank=True, help_text='可以用于记录当前表单数据json格式') ticket_data = models.JSONField('工单数据', default=dict, blank=True, help_text='可以用于记录当前表单数据json格式')
intervene_type = models.IntegerField('干预类型', default=0, help_text='流转类型', choices=Transition.intervene_type_choices) intervene_type = models.IntegerField('干预类型', default=0, help_text='流转类型', choices=Transition.intervene_type_choices)
participant_cc = models.JSONField('抄送给', default=list, blank=True, help_text='抄送给(userid列表)')
class WfScript(CommonAModel): class WfScript(CommonAModel):
""" """
@ -228,7 +232,7 @@ class WfScript(CommonAModel):
(1, '获取处理人'), (1, '获取处理人'),
(2, '执行操作'), (2, '执行操作'),
) )
usage = models.IntegerField('脚本用途', default=1, choices=usage_choices) usage = models.IntegerField('脚本用途', default=2, choices=usage_choices)
wait = models.BooleanField('是否等待执行完成', default=True) wait = models.BooleanField('是否等待执行完成', default=True)
name = models.CharField('脚本名称', max_length=100) name = models.CharField('脚本名称', max_length=100)
workflow = models.ForeignKey(Workflow, verbose_name='关联工作流', null=True, blank=True, on_delete=models.SET_NULL) workflow = models.ForeignKey(Workflow, verbose_name='关联工作流', null=True, blank=True, on_delete=models.SET_NULL)

View File

@ -8,7 +8,8 @@ class GetParticipants:
# # return list(filter(lambda x: x.startswith('get_') and callable(getattr(self, x)), dir(self))) # # return list(filter(lambda x: x.startswith('get_') and callable(getattr(self, x)), dir(self)))
# return [(func, getattr(self, func).__doc__) for func in dir(self) if callable(getattr(self, func)) and func.startswith('get_')] # return [(func, getattr(self, func).__doc__) for func in dir(self) if callable(getattr(self, func)) and func.startswith('get_')]
def get_create_by(self, state:dict={}, ticket:dict={}, ticket_data:dict={}, request={}): @classmethod
def get_create_by(cls, state:dict={}, ticket:dict={}, ticket_data:dict={}, request={}):
"""工单创建人""" """工单创建人"""
participant = ticket.create_by.id participant = ticket.create_by.id
return participant return participant

View File

@ -8,6 +8,7 @@ from django.utils import timezone
from datetime import timedelta from datetime import timedelta
import random import random
from .scripts import GetParticipants from .scripts import GetParticipants
from utils.queryset import get_parent_queryset
class WfService(object): class WfService(object):
@staticmethod @staticmethod
@ -158,12 +159,15 @@ class WfService(object):
elif destination_participant_type == State.PARTICIPANT_TYPE_ROLE:#角色 elif destination_participant_type == State.PARTICIPANT_TYPE_ROLE:#角色
user_queryset = User.objects.filter(roles__in=destination_participant) user_queryset = User.objects.filter(roles__in=destination_participant)
# 如果选择了角色, 需要走过滤策略 # 如果选择了角色, 需要走过滤策略
if ticket.filter_policy == 1: if state.filter_policy == 1:
user_queryset = user_queryset.filter(dept=ticket.belong_dept) depts = get_parent_queryset(ticket.belong_dept)
elif ticket.filter_policy == 2: user_queryset = user_queryset.filter(dept__in=depts)
user_queryset = user_queryset.filter(dept=ticket.create_by.dept) elif state.filter_policy == 2:
elif ticket.filter_policy == 3: depts = get_parent_queryset(ticket.create_by.dept)
user_queryset = user_queryset.filter(dept=request.user.dept) user_queryset = user_queryset.filter(dept__in=depts)
elif state.filter_policy == 3:
depts = get_parent_queryset(request.user.dept)
user_queryset = user_queryset.filter(dept__in=depts)
destination_participant = list(user_queryset.values_list('id', flat=True)) destination_participant = list(user_queryset.values_list('id', flat=True))
if type(destination_participant) == list: if type(destination_participant) == list:
destination_participant_type = State.PARTICIPANT_TYPE_MULTI destination_participant_type = State.PARTICIPANT_TYPE_MULTI

View File

@ -18,6 +18,7 @@ from rest_framework import status
from django.db.models import Count from django.db.models import Count
from .scripts import GetParticipants from .scripts import GetParticipants
# Create your views here. # Create your views here.
class FromCodeListView(APIView): class FromCodeListView(APIView):
def get(self, request, format=None): def get(self, request, format=None):
@ -144,6 +145,7 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin
if key not in ticket_data or not ticket_data[key]: if key not in ticket_data or not ticket_data[key]:
raise APIException('字段{}必填'.format(key)) raise APIException('字段{}必填'.format(key))
ticket = serializer.save(state=start_state, create_by=request.user, act_state=Ticket.TICKET_ACT_STATE_DRAFT, belong_dept=request.user.dept) # 先创建出来 ticket = serializer.save(state=start_state, create_by=request.user, act_state=Ticket.TICKET_ACT_STATE_DRAFT, belong_dept=request.user.dept) # 先创建出来
next_state = WfService.get_next_state_by_transition_and_ticket_info(ticket=ticket, transition=transition) next_state = WfService.get_next_state_by_transition_and_ticket_info(ticket=ticket, transition=transition)
participant_info = WfService.get_ticket_state_participant_info(state=next_state, ticket=ticket, ticket_data=ticket.ticket_data) participant_info = WfService.get_ticket_state_participant_info(state=next_state, ticket=ticket, ticket_data=ticket.ticket_data)
destination_participant_type = participant_info.get('destination_participant_type', 0) destination_participant_type = participant_info.get('destination_participant_type', 0)
@ -174,6 +176,16 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin
TicketFlow.objects.create(ticket=ticket, state=start_state, ticket_data=WfService.get_ticket_all_field_value(ticket), TicketFlow.objects.create(ticket=ticket, state=start_state, ticket_data=WfService.get_ticket_all_field_value(ticket),
suggestion=rdata.get('suggestion',''), participant_type=State.PARTICIPANT_TYPE_PERSONAL, suggestion=rdata.get('suggestion',''), participant_type=State.PARTICIPANT_TYPE_PERSONAL,
participant=ticket.create_by, transition=transition) participant=ticket.create_by, transition=transition)
# 开始状态需要抄送
if start_state.participant_cc:
TicketFlow.objects.create(ticket=ticket, state=ticket.start_state,
participant_type=0, intervene_type=Transition.TRANSITION_INTERVENE_TYPE_CC,
participant=None, participant_cc=start_state.participant_cc)
# 目标状态需要抄送
if next_state.participant_cc:
TicketFlow.objects.create(ticket=ticket, state=next_state,
participant_type=0, intervene_type=Transition.TRANSITION_INTERVENE_TYPE_CC,
participant=None, participant_cc=next_state.participant_cc)
return Response(TicketSerializer(instance=ticket).data) return Response(TicketSerializer(instance=ticket).data)
@action(methods=['get'], detail=False, perms_map={'get':'*'}) @action(methods=['get'], detail=False, perms_map={'get':'*'})
@ -228,7 +240,7 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin
destination_participant = [] destination_participant = []
for key, value in multi_all_person.items(): for key, value in multi_all_person.items():
if not value: if not value:
destination_participant.push(key) destination_participant.append(key)
else: else:
# 当前处理人类型非全部处理 # 当前处理人类型非全部处理
participant_info = WfService.get_ticket_state_participant_info(destination_state, ticket, data['ticket_data']) participant_info = WfService.get_ticket_state_participant_info(destination_state, ticket, data['ticket_data'])
@ -262,6 +274,11 @@ class TicketViewSet(OptimizationMixin, CreateUpdateCustomMixin, CreateModelMixin
TicketFlow.objects.create(ticket=ticket, state=source_state, ticket_data=WfService.get_ticket_all_field_value(ticket), TicketFlow.objects.create(ticket=ticket, state=source_state, ticket_data=WfService.get_ticket_all_field_value(ticket),
suggestion=data.get('suggestion',''), participant_type=State.PARTICIPANT_TYPE_PERSONAL, suggestion=data.get('suggestion',''), participant_type=State.PARTICIPANT_TYPE_PERSONAL,
participant=request.user, transition=transition) participant=request.user, transition=transition)
# 目标状态需要抄送
if destination_state.participant_cc:
TicketFlow.objects.create(ticket=ticket, state=destination_state,
participant_type=0, intervene_type=Transition.TRANSITION_INTERVENE_TYPE_CC,
participant=None, participant_cc=destination_state.participant_cc)
return Response(TicketSerializer(instance=ticket).data) return Response(TicketSerializer(instance=ticket).data)

View File

@ -5,44 +5,34 @@ 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, Step from apps.mtm.models import Material, Step, RecordForm
class Good(CommonAModel): class Product(CommonAModel):
""" """
物品 产品(所有生产过程中出现过的)
""" """
act_state_choices=( act_state_choices=(
(0, '待执行'), (0, '待执行'),
(1, '进行中'), (1, '进行中'),
(2, '已完成') (2, '已完成')
) )
number = models.CharField('物品编号', primary_key=True, null=True, blank=True, max_length=50) number = models.CharField('物品编号', unique=True, null=True, blank=True, max_length=50)
m_state = models.ForeignKey(Material, verbose_name='所属物料状态', on_delete=models.CASCADE) m_state = models.ForeignKey(Material, verbose_name='所属物料状态', on_delete=models.CASCADE)
p_state = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True) p_state = models.ForeignKey(Step, verbose_name='所在步骤', on_delete=models.CASCADE, null=True, blank=True)
act_state = models.IntegerField('进行状态', default=0) act_state = models.IntegerField('进行状态', default=0)
parent = models.ForeignKey('self', verbose_name='上一级', on_delete=models.CASCADE, db_constraint=False)
remark = models.CharField('备注', max_length=200, null=True, blank=True)
class ProductForm(CommonAModel):
class GoodFlow(BaseModel):
""" """
物品流转日志 记录表格
""" """
pass record_form = models.ForeignKey(RecordForm, verbose_name='所用表格', on_delete=models.CASCADE)
data = models.JSONField('记录的数据', default=dict, blank=True)
class Vendor(CommonAModel): class ProductFlow(BaseModel):
""" """
供应商信息 产品流转日志
""" """
product = models.ForeignKey(Product, verbose_name='产品', on_delete=models.CASCADE)
name = models.CharField('供应商名称', max_length=50, unique=True)
contact = models.CharField('联系人', max_length=20)
contact_phone = models.CharField('联系电话', max_length=11, unique=True)
address = models.CharField('地址', max_length=200, null=True, blank=True)
description = models.CharField('描述', max_length=200, blank=True, null=True)
material = models.CharField('供应的物料', max_length=200, blank=True, null=True)
class Meta:
verbose_name = '供应商信息'
verbose_name_plural = verbose_name
def __str__(self):
return self.name

View File

@ -1,9 +1,2 @@
from rest_framework.serializers import ModelSerializer from rest_framework.serializers import ModelSerializer
from .models import Vendor
class VendorSerializer(ModelSerializer):
class Meta:
model = Vendor
fields = '__all__'

View File

@ -1,11 +1,10 @@
from django.db.models import base from django.db.models import base
from rest_framework import urlpatterns from rest_framework import urlpatterns
from apps.pum.views import VendorViewSet
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('vendor', VendorViewSet, basename='vendor')
urlpatterns = [ urlpatterns = [
path('', include(router.urls)), path('', include(router.urls)),
] ]

View File

@ -1,23 +1,6 @@
from django.shortcuts import render from django.shortcuts import render
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from apps.pum.models import Vendor
from apps.pum.serializers import VendorSerializer
from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin from apps.system.mixins import CreateUpdateModelAMixin, OptimizationMixin
# Create your views here.
# Create your views here.
class VendorViewSet(CreateUpdateModelAMixin, ModelViewSet):
"""
供应商-增删改查
"""
perms_map = {'get': '*', 'post': 'vendor_create',
'put': 'vendor_update', 'delete': 'vendor_delete'}
queryset = Vendor.objects.all()
serializer_class = VendorSerializer
search_fields = ['name', 'contact']
filterset_fields = []
ordering_fields = ['create_time']
ordering = ['-create_time']

View File

@ -57,4 +57,14 @@ def get_child_queryset2(obj, hasParent=True):
while child_queryset: while child_queryset:
queryset = queryset | child_queryset queryset = queryset | child_queryset
child_queryset = cls.objects.filter(parent__in=child_queryset) child_queryset = cls.objects.filter(parent__in=child_queryset)
return queryset return queryset
def get_parent_queryset(obj, hasSelf=True):
cls = type(obj)
ids = []
if hasSelf:
ids.append(obj.id)
while obj.parent:
obj = obj.parent
ids.append(obj.id)
return cls.objects.filter(id__in=ids)