Commit 19715ad3 by 夏超

[fix] 生产进度查询

parent 57d0383c
......@@ -22,6 +22,7 @@
],
'qweb': [
"static/src/xml/roke_craft_design.xml",
"static/src/xml/main_task.xml",
],
'application': False,
'installable': True,
......
......@@ -4,3 +4,4 @@ from . import inherit_production_task
from . import material
from . import salary_excel
from . import inherit_picking
from . import main_or_task_data
import logging
import os
from jinja2 import FileSystemLoader, Environment
import pytz
from odoo import models, fields, api, http, SUPERUSER_ID, _
from odoo.addons.roke_workstation_api.controllers.data_analysis import reduce_pytz_conversion, pytz_conversion
from odoo.addons.roke_workstation_api.controllers.work_order import RokeWorkstationWorkOrder
from odoo.addons.roke_mes_entrust_order.controller.main import Main
_logger = logging.getLogger(__name__)
# 设置查找html文件的路径
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
templateloader = FileSystemLoader(searchpath=BASE_DIR + "/static")
env = Environment(loader=templateloader)
class RokeWorkstationTaskModel(http.Controller):
@http.route('/roke/main_task/index', type='http', auth='user', csrf=False, cors="*")
def roke_main_task_index(self, **kwargs):
user_id = http.request.env.user.id
values = {
"user_id": user_id
}
template = env.get_template('/src/html/view/main_task.html')
html = template.render(values)
return html
@staticmethod
def _get_product_image_avatar_url(_id):
attachment = http.request.env['ir.attachment'].sudo().search([
("res_model", "=", "roke.product"), ("res_id", "=", _id),
("res_field", "=", "image_1920")
])
if not attachment.access_token:
attachment.generate_access_token()
return f"/web/image/{attachment.id}?access_token={attachment.access_token}&unique=" \
f"{str(fields.Datetime.now().timestamp())}"
@http.route('/roke/workstation/get_main_task_data', type='json', methods=['POST', 'OPTIONS'], auth="none",
csrf=False, cors='*')
def get_main_task_data(self):
_self = http.request
limit = _self.jsonrequest.get("limit", 20)
page = _self.jsonrequest.get("page", 1)
state = _self.jsonrequest.get("state", False)
priority = _self.jsonrequest.get("priority", False)
task_code = _self.jsonrequest.get("task_code", False)
domain = ["|", ("task_type", "=", "main"), ("task_type", "=", False)]
if task_code:
domain = [("code", "ilike", task_code)]
if state:
domain.append(("state", "=", state))
if priority:
domain.append(("priority", "=", priority))
task_ids = _self.env["roke.production.task"].sudo().search(domain, limit=limit, offset=(page - 1) * limit,
order="code desc")
task_counts = _self.env["roke.production.task"].sudo().search_count(domain)
task_list = []
complete_basis = _self.env.user.company_id.complete_basis
def get_work_order(_task, _complete_basis):
work_list = []
for work in _task.work_order_ids:
if hasattr(work, "is_entrust") and work.is_entrust:
work_state = "未开工" if work.entrust_state == "未发料" else \
("进行中" if work.state == "未完工" else ("已完工" if work.state != "暂停" else "暂停"))
else:
work_state = work.wo_start_state if work.wo_start_state == "未开工" else \
("进行中" if work.state == "未完工" else ("已完工" if work.state != "暂停" else "暂停"))
work_data = {
"id": work.id,
"code": work.code,
"process_id": work.process_id.id,
"state": work_state,
"process_name": work.process_id.name,
"progress": 0 if work.plan_qty == 0 else
round(((work.finish_qty if _complete_basis in ["合格数", "手动完工"] else
(work.finish_qty + work.unqualified_qty)) / work.plan_qty) * 100, 2)
}
work_list.append(work_data)
return {
"code": _task.code or "",
"product_id": _task.product_id.id or 0,
"product_name": _task.product_id.name or "",
"product_image_url": self._get_product_image_avatar_url(_task.product_id.id),
"state": _task.state or "",
"priority": _task.priority or "",
"unqualified_qty": sum(_task.work_order_ids.mapped("unqualified_qty")) or 0,
"work_order": work_list
}
if task_code:
for v in task_ids:
data = get_work_order(v, complete_basis)
task_list.append(data)
return {"code": 0, "message": "获取成功", "data": task_list, "count": task_counts}
for v in task_ids:
data = get_work_order(v, complete_basis)
sub_task = _self.env["roke.production.task"].sudo().search([("task_type", "=", "sub"),
("main_task_code", "=", v.code)],
order="code asc")
data["children"] = [get_work_order(child, complete_basis) for child in sub_task]
task_list.append(data)
return {"code": 0, "message": "获取成功", "data": task_list, "count": task_counts}
......@@ -24,9 +24,9 @@ class InheritProductionTask(models.Model):
task_type = fields.Selection([
('main', '主任务'),
('sub', '子任务')
], string='任务类型', compute='_compute_task_type')
], string='任务类型', compute='_compute_task_type', store=True)
main_task_code = fields.Char(string='主任务编号', compute='_compute_main_task_code', index=True)
main_task_code = fields.Char(string='主任务编号', compute='_compute_main_task_code', index=True, store=True)
flowing_water = fields.Char(string="物料流水")
......
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>生产进度查看</title>
<meta content="width=device-width,initial-scale=1.0, maximum-scale=1.0,user-scalable=0" name="viewport" />
<link rel="stylesheet" href="/sdddl_project/static/src/html/element-ui/index.css" />
<script src="/sdddl_project/static/src/html/js/vue.js"></script>
<script src="/sdddl_project/static/src/html/js/axios.min.js"></script>
<script src="/sdddl_project/static/src/html/element-ui/index.js"></script>
</head>
<body id="bodyId" style="display: none">
<div id="app" v-loading.body.fullscreen.lock="loading">
<el-card class="pageCardBox">
<div class="filterAreaBox">
<el-input class="width_sty" v-model="code_value" placeholder="请输入任务编号查询" clearable @change="code_query" @clear="code_query"></el-input>
<el-select class="width_sty" v-model="selStateValue" placeholder="请选择状态状态查询" size="small" clearable @change="selChangeHandle">
<el-option label="未完工" value="未完工"></el-option>
<el-option label="已完工" value="已完工"></el-option>
<el-option label="强制完工" value="强制完工"></el-option>
<el-option label="暂停" value="暂停"></el-option>
<el-option label="取消" value="取消"></el-option>
</el-select>
<el-select class="width_sty" v-model="selPriorityValue" placeholder="请选择优先级查询" size="small" clearable
@change="selChangeHandle">
<el-option label="1级" value="1级"></el-option>
<el-option label="2级" value="2级"></el-option>
<el-option label="3级" value="3级"></el-option>
<el-option label="4级" value="4级"></el-option>
<el-option label="5级" value="5级"></el-option>
</el-select>
</div>
<el-table :data="taskWorkDataList" class="tableAreaBox" border :height="1" row-key="code"
:header-cell-style="{backgroundColor:'#eaf4ff'}">
<el-table-column prop="code" label="任务编号" width="155" align="center"></el-table-column>
<el-table-column prop="product_name" label="产品名称" width="120" align="center"
show-overflow-tooltip></el-table-column>
<el-table-column label="状态" width="80" align="center">
<template slot-scope="{row}">
<span :style="{color: getColorFn(row.state)}">[[row.state]]</span>
</template>
</el-table-column>
<el-table-column label="优先级" width="80" align="center">
<template slot-scope="{row}">
<span :style="{color: getColorFn(row.priority)}">[[row.priority]]</span>
</template>
</el-table-column>
<el-table-column prop="unqualified_qty" label="不良品数" width="80" align="center"></el-table-column>
<el-table-column label="进度" align="center">
<template slot-scope="{row}">
<div class="progressCellBox">
<div class="progressItemBox" v-for="(item, index) in row.work_order" :key="index">
<div class="progressInfoBox">
<el-progress type="circle" :percentage="item.progress" :width="40"
:stroke-width="3" :define-back-color="process_progress_colo(item.state)" :color="process_progress_colo(item.state)"></el-progress>
<span class="progressLabel">[[item.process_name]]</span>
</div>
<div class="cuttingLineBox" v-if="index!=(row.work_order.length-1)"></div>
</div>
</div>
</template>
</el-table-column>
</el-table>
<div class="paginationBox">
<el-pagination background layout="prev, pager, next" :total="taskWorkDataTotal"
@current-change="getTaskWorkDataListApi" :current-page="taskWorkDataPage"></el-pagination>
</div>
</el-card>
</div>
</body>
<script>
// 发送消息给父页面(关闭odoo的菜单弹窗)
document.addEventListener("click", () => {
window.parent.postMessage("hidePopover", "*")
})
let vue = new Vue({
el: "#app",
delimiters: ["[[", "]]"], // 替换原本vue的[[ key ]]取值方式(与odoo使用的jinja2冲突问题)
data() {
return {
windowHeight: window.innerHeight, // 窗口高度
baseURL: "", // 基地址 http://192.168.8.92:8069
loading: false, // 全局加载效果
selStateValue: null, // 状态下拉选择框的值
selPriorityValue: null, // 优先级下拉选择框的值
taskWorkDataList: [], // 任务工单列表
taskWorkDataTotal: 0, // 数据条数总数
taskWorkDataPage: 1, // 数据页码
taskType_val:'主任务', //任务类型
code_value:null, //任务编号
}
},
computed: {
imageList() {
let list = []
this.taskWorkDataList.forEach((item, index) => {
if (item.product_image_url) list.push(item.product_image_url)
})
return list
}
},
created() {
// 获取任务工单列表
this.getTaskWorkDataListApi()
},
mounted() {
this.$nextTick(() => {
// 防止出现乱码情况
document.getElementById("bodyId").style.display = "block"
})
// 开启页面大小变化监听器
window.addEventListener("resize", this.handleResize)
},
methods: {
// 获取任务工单列表
getTaskWorkDataListApi(val) {
if (val) this.taskWorkDataPage = val
this.loading = true
axios({
method: "POST",
url: this.baseURL + "/roke/workstation/get_main_task_data",
data: {
page: this.taskWorkDataPage,
limit: 10,
state: this.selStateValue,
priority: this.selPriorityValue,
task_code:this.code_value
},
headers: { "Content-Type": "application/json" },
}).then((result) => {
if (result?.data?.result?.code == 0) {
const data = result.data.result
let imageIndex = 0
data.data.forEach((item, index) => {
if (item.product_image_url) {
item.product_image_url = this.baseURL + item.product_image_url
item['zIndex'] = imageIndex
imageIndex++
}
})
this.taskWorkDataTotal = data.count
this.taskWorkDataList = data.data
} else if (result?.data?.result?.code == 1) {
this.$message.error(result.data.result.message)
} else if (result?.data?.error) {
this.$message.error(result.data.error.message)
}
}).catch((error) => {
this.$message.error("获取任务工单列表失败!")
}).finally(() => {
this.loading = false
})
},
// 处理窗口大小变化修改图表大小
handleResize() {
this.windowHeight = window.innerHeight
},
// 获取颜色方法
getColorFn(text) {
if (text == '未完工') {
return '#3385ff'
} else if (text == '已完工' || text == '正常') {
return '#00b442'
} else if (text == '强制完工') {
return '#746c96'
} else if (text == '暂停' || text == '紧急') {
return '#ffbd01'
} else if (text == '非常紧急') {
return '#ff0200'
} else {
return "#666666"
}
},
// 工序进度状态
process_progress_colo(state) {
if (state == '进行中') {
return '#00b442'
} else if (state == '已完工') {
return '#3385ff'
} else if (state == '暂停') {
return '#ffbd01'
}
},
// 下拉框改变事件
selChangeHandle(val) {
this.taskWorkDataPage = 1
this.getTaskWorkDataListApi()
},
// 任务编号查询
code_query(e){
this.taskWorkDataPage = 1
this.getTaskWorkDataListApi()
}
},
beforeDestroy() {
// 页面销毁移除resize事件监听
window.removeEventListener("resize", this.handleResize)
}
})
</script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-thumb {
background: #c0c4cc;
border-radius: 3px;
}
::-webkit-scrollbar-track {
background: #f5f7fa;
}
#app {
width: 100vw;
height: 100vh;
padding: 8px;
background-color: #f1f2f4;
.pageCardBox {
height: 100%;
.el-card__body {
padding: 8px;
height: 100%;
display: flex;
flex-direction: column;
}
}
.filterAreaBox {
display: flex;
margin-bottom: 8px;
gap: 10px;
.width_sty{
width: 15%;
}
}
.tableAreaBox {
border-radius: 4px;
overflow: hidden;
.imageBox {
max-height: 100px;
}
.progressCellBox {
width: 100%;
display: flex;
align-items: center;
overflow-x: auto;
.progressItemBox {
display: flex;
.progressInfoBox {
display: flex;
flex-direction: column;
align-items: center;
.el-progress__text {
font-size: 9px !important;
}
.progressLabel {
font-size: 12px;
color: #606266;
}
}
.cuttingLineBox {
width: 20px;
height: 2px;
margin-top: 20px;
background-color: #eeeeee;
}
}
}
}
.paginationBox {
display: flex;
align-items: center;
flex-direction: row-reverse;
margin-top: 8px;
}
}
.el-input--small .el-input__inner {
height: 40px;
line-height: 40px;
}
.el-table__expand-icon{
font-size: 20px;
color: #000;
}
</style>
</html>
\ No newline at end of file
odoo.define('sdddl_project.main_task', function (require) {
"use strict";
var core = require('web.core');
var session = require('web.session');
var AbstractAction = require('web.AbstractAction');
const Dialog = require("web.Dialog");
var RokeCraftDesign = AbstractAction.extend({
template: 'sdddl_project.main_task',
init: function (parent, action, params) {
this.action_controller = `${action.params.controller}`
return this._super.apply(this, arguments);
},
});
core.action_registry.add('sdddl_project.main_task', RokeCraftDesign);
return RokeCraftDesign;
});
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" ?>
<templates id="roke_routing_settings_template" xml:space="preserve">
<t t-name="sdddl_project.main_task">
<iframe id="main_task" t-attf-src="#{widget.action_controller}" frameBorder="no" width="100%" height="100%" />
</t>
</templates>
\ No newline at end of file
......@@ -5,6 +5,7 @@
<!-- <script type="text/javascript" src="/roke_pub_wx_notice/static/src/js/sync_wx_btn.js"/>-->
<script type="text/javascript" src="/sdddl_project/static/src/js/button.js"/>
<script type="text/javascript" src="/sdddl_project/static/src/js/roke_craft_design.js"/>
<script type="text/javascript" src="/sdddl_project/static/src/js/main_task.js"/>
</xpath>
</template>
</odoo>
......@@ -40,4 +40,16 @@
</xpath>
</field>
</record>
<record id="action_roke_main_task" model="ir.actions.client">
<field name="name">生产进度查看</field>
<field name="tag">sdddl_project.main_task</field>
<field name="params" eval="{
'controller': '/roke/main_task/index'
}"/>
<field name="target">current</field>
</record>
<menuitem id="menu_action_roke_main_task" parent="roke_mes_production.roke_production_report_menu" sequence="92" name="生产进度查看" action="action_roke_main_task" groups="base.group_system"/>
</odoo>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment