| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766 |
- <template>
- <ele-modal
- :before-close="cancel"
- :close-on-click-modal="false"
- :maxable="true"
- :title="title"
- :visible.sync="detailsVisible"
- append-to-body
- custom-class="ele-dialog-form task-report-dialog"
- width="75vw"
- >
- <el-form
- ref="form"
- :model="form"
- :rules="rules"
- label-position="right"
- label-width="110px"
- >
- <el-row>
- <headerTitle style="margin-top: 15px" title="报工信息"></headerTitle>
- <el-col :lg="12" :md="12" :sm="12" :xl="12" :xs="12">
- <el-form-item
- :rules="{
- required: true,
- message: '请选择实际开始时间',
- trigger: 'change'
- }"
- label="实际开始时间"
- prop="realStartTime"
- >
- <el-date-picker
- v-model="form.realStartTime"
- :disabled="inputDis"
- class="time_select"
- placeholder="选择实际开始时间"
- type="datetime"
- value-format="yyyy-MM-dd HH:mm:ss"
- @change="handleTimeChange"
- ></el-date-picker>
- </el-form-item>
- </el-col>
- <el-col :lg="12" :md="12" :sm="12" :xl="12" :xs="12">
- <el-form-item
- :rules="{
- required: true,
- message: '请选择实际结束时间',
- trigger: 'change'
- }"
- label="实际结束时间"
- prop="realEndTime"
- >
- <el-date-picker
- v-model="form.realEndTime"
- :disabled="inputDis"
- class="time_select"
- placeholder="选择实际结束时间"
- type="datetime"
- value-format="yyyy-MM-dd HH:mm:ss"
- @change="handleTimeChange"
- ></el-date-picker>
- </el-form-item>
- </el-col>
- <!-- <el-col :lg="12" :md="12" :sm="12" :xl="12" :xs="12">
- <el-form-item label="合格数量" prop="qualifiedQuantity">
- <el-input
- v-model.number="form.qualifiedQuantity"
- :disabled="inputDis"
- placeholder="请输入"
- type="number"
- @input="(e) => handleQuantityInput(e, 'qualifiedQuantity')"
- ></el-input>
- </el-form-item>
- </el-col> -->
- <!-- <el-col :lg="12" :md="12" :sm="12" :xl="12" :xs="12">
- <el-form-item label="不合格数量" prop="unqualifiedQuantity">
- <el-input
- v-model.number="form.unqualifiedQuantity"
- :disabled="inputDis"
- placeholder="请输入"
- type="number"
- @input="(e) => handleQuantityInput(e, 'unqualifiedQuantity')"
- ></el-input>
- </el-form-item>
- </el-col> -->
- <!-- <el-col :lg="12" :md="12" :sm="12" :xl="12" :xs="12">
- <el-form-item label="合格重量" prop="qualifiedWeight">
- <el-input
- v-model.number="form.qualifiedWeight"
- :disabled="inputDis"
- placeholder="请输入"
- type="number"
- @input="(e) => handleWeightInput(e, 'qualifiedWeight')"
- ></el-input>
- </el-form-item>
- </el-col> -->
- <!-- <el-col :lg="12" :md="12" :sm="12" :xl="12" :xs="12">
- <el-form-item label="不合格重量" prop="unqualifiedWeight">
- <el-input
- v-model.number="form.unqualifiedWeight"
- :disabled="inputDis"
- placeholder="请输入"
- type="number"
- @input="(e) => handleWeightInput(e, 'unqualifiedWeight')"
- ></el-input>
- </el-form-item>
- </el-col> -->
- <el-col :lg="12" :md="12" :sm="12" :xl="12" :xs="12">
- <el-form-item label="报工数" prop="reportQuantity">
- <el-input
- v-model.number="form.reportQuantity"
- :disabled="inputDis"
- placeholder="请输入"
- @input="(e) => handleQuantityInput(e, 'reportQuantity')"
- ></el-input>
- </el-form-item>
- </el-col>
- <el-col :lg="12" :md="12" :sm="12" :xl="12" :xs="12">
- <el-form-item label="损耗数" prop="lossQuantity">
- <el-input
- v-model.number="form.lossQuantity"
- :disabled="inputDis"
- placeholder="请输入"
- @input="(e) => handleQuantityInput(e, 'lossQuantity')"
- ></el-input>
- </el-form-item>
- </el-col>
- <el-col :span="24">
- <el-form-item label="备注信息">
- <el-input
- v-model="form.remark"
- :disabled="inputDis"
- :rows="2"
- placeholder="请输入"
- type="textarea"
- ></el-input>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row class="tool_btn" v-if="!inputDis">
- <el-button
- type="primary"
- size="medium"
- @click="submitAdd"
- :loading="loadingBtn"
- >报工</el-button
- >
- </el-row>
- <headerTitle style="margin-top: 15px" title="工单信息"></headerTitle>
- <el-row :gutter="10" class="basic">
- <el-col
- v-for="item in fieldMap.orderList"
- :key="item.prop"
- :lg="8"
- :md="12"
- :sm="12"
- :xl="8"
- :xs="12"
- >
- <el-form-item :label="item.label" class="form80">
- <el-input v-model="current[item.prop]" disabled>
- <template slot="append" v-if="item.label == '要求生产数量:'">
- {{ current['measuringUnit'] }}
- </template>
- <template slot="append" v-if="item.label == '要求生产重量:'">
- {{ current['newWeightUnit'] }}
- </template>
- </el-input>
- </el-form-item>
- </el-col>
- </el-row>
- <headerTitle style="margin-top: 15px" title="任务信息"></headerTitle>
- <el-row :gutter="10" class="basic">
- <el-col
- v-for="item in fieldMap.taskList"
- :key="item.prop"
- :lg="8"
- :md="12"
- :sm="12"
- :xl="8"
- :xs="12"
- >
- <el-form-item :label="item.label" class="form80">
- <el-input v-model="current[item.prop]" disabled>
- <template slot="append" v-if="item.label == '任务数量:'">
- {{ current['measuringUnit'] }}
- </template>
- <template slot="append" v-if="item.label == '任务重量:'">
- {{ current['newWeightUnit'] }}
- </template>
- </el-input>
- </el-form-item>
- </el-col>
- </el-row>
- <el-row v-if="title === '详情'">
- <headerTitle style="margin-top: 15px" title="报工记录"></headerTitle>
- <ModifyRecord ref="ModifyRecordRef" :list="list" />
- </el-row>
- <div slot="footer" class="tool_btn">
- <el-button @click="cancel">关闭</el-button>
- </div>
- </el-form>
- </ele-modal>
- </template>
- <script>
- import {
- listWorkCenter,
- batchUpdateRealTime,
- listUpdateRealTimeRecord
- } from '@/api/workOrderList';
- import ModifyRecord from '@/views/taskList/components/ModifyRecord.vue';
- export default {
- components: {
- ModifyRecord
- },
- props: {
- currentRow: {
- type: Object,
- default: () => ({})
- }
- },
- data() {
- return {
- title: '详情',
- form: {
- realEndTime: '',
- realStartTime: '',
- unqualifiedWeight: '',
- unqualifiedQuantity: '',
- qualifiedWeight: '',
- qualifiedQuantity: '',
- remark: '',
- reportQuantity: '',
- lossQuantity: '',
- workOrderCode: '',
- workOrderId: '',
- taskId: ''
- },
- rules: {
- // qualifiedQuantity: [
- // {
- // required: true,
- // message: '请输入合格数量',
- // trigger: 'blur'
- // }
- // ],
- // qualifiedWeight: [
- // {
- // required: true,
- // message: '请输入合格重量',
- // trigger: 'blur'
- // }
- // ],
- // unqualifiedQuantity: [
- // {
- // required: true,
- // message: '请输入不合格数量',
- // trigger: 'blur'
- // }
- // ],
- // unqualifiedWeight: [
- // {
- // required: true,
- // message: '请输入不合格重量',
- // trigger: 'blur'
- // }
- // ]
- reportQuantity: [
- {
- required: true,
- message: '请输入报工数量',
- trigger: 'blur'
- }
- ],
- lossQuantity: [
- {
- required: true,
- message: '请输入损耗数量',
- trigger: 'blur'
- }
- ]
- },
- current: {},
- detailsVisible: false,
- fieldMap: {
- orderList: [
- { label: '计划批次号:', prop: 'batchNo' },
- { label: '工单编码:', prop: 'mesWorkOrderCode' },
- { label: '编码', prop: 'productCode' },
- { label: '名称', prop: 'productName' },
- { label: '规格', prop: 'specification' },
- { label: '生产订单编码:', prop: 'workOrderCode' },
- { label: '计划编号:', prop: 'productionPlanCode' },
- { label: '工艺路线:', prop: 'produceRoutingName' },
- { label: '要求生产数量:', prop: 'formingNum' },
- { label: '要求生产重量:', prop: 'formingWeight' },
- { label: '所属工厂:', prop: 'factoryName' },
- { label: '所属班组:', prop: 'assignTeamName' },
- { label: '计划开始时间:', prop: 'planStartTime' },
- { label: '计划结束时间:', prop: 'planCompleteTime' }
- ],
- taskList: [
- { label: '任务编码:', prop: 'assignCode' },
- { label: '工序名称:', prop: 'taskName' },
- { label: '执行类型:', prop: 'assigneeType' },
- { label: '执行对象名称:', prop: 'assigneeName' },
- { label: '工时:', prop: 'durationText' },
- { label: '任务开始时间:', prop: 'startTime' },
- { label: '任务结束时间:', prop: 'endTime' },
- { label: '任务数量:', prop: 'quantity' },
- { label: '任务重量:', prop: 'weight' }
- ]
- },
- loadingBtn: false,
- list: [],
- reportNum: '',
- lossNum: ''
- };
- },
- computed: {
- inputDis() {
- return this.title === '详情';
- }
- },
- methods: {
- open(type, row, form) {
- console.log(type, row, form, 'type, row, form');
- this.title = type === 'report' ? '报工' : '详情';
- this.detailsVisible = true;
- this.current = { ...row };
- if (form.realEndTime) {
- this.$nextTick(() => {
- this.form = { ...form };
- });
- if (type !== 'report') {
- listUpdateRealTimeRecord(row.apsAssigneeId)
- .then((res) => {
- if (res) {
- this.list = res;
- }
- })
- .catch((err) => {
- this.$message.error(err.message);
- });
- }
- }
- // 累计已报工、已损耗(来自任务行,勿用表单预填的本次可报剩余)
- this.reportNum = Number(this.current.reportQuantityReported) || 0;
- this.lossNum = Number(this.current.lossQuantityReported) || 0;
- this.getData();
- },
- cancel() {
- this.form = {
- realEndTime: '',
- realStartTime: '',
- unqualifiedWeight: '',
- unqualifiedQuantity: '',
- qualifiedWeight: '',
- qualifiedQuantity: '',
- remark: '',
- reportQuantity: '',
- lossQuantity: '',
- workOrderCode: '',
- workOrderId: '',
- taskId: ''
- };
- this.$refs.form.resetFields();
- this.detailsVisible = false;
- },
- async getData() {
- try {
- const res = await listWorkCenter(this.current.firstTaskId);
- this.$set(this.current, 'factoryName', res[0].factoryName);
- } catch (err) {
- this.$message.warning(err.message);
- }
- },
- // 时间选择
- handleTimeChange() {
- // 如果结束时间早于开始时间,清空结束时间
- // if (this.form.realStartTime && this.current.startTime) {
- // const realStartTime = new Date(this.form.realStartTime).getTime();
- // const realEndTime = new Date(this.current.startTime).getTime();
- // if (realStartTime < realEndTime) {
- // this.form.realStartTime = '';
- // this.$message.warning('实际开始时间不能早于任务开始时间');
- // }
- // }
- // if (this.form.realStartTime && this.form.realEndTime) {
- // const realStartTime = new Date(this.form.realStartTime).getTime();
- // const realEndTime = new Date(this.form.realEndTime).getTime();
- // if (realStartTime > realEndTime) {
- // this.form.realEndTime = '';
- // this.$message.warning('结束时间不能早于开始时间');
- // }
- // }
- },
- // 重量正则判断
- handleWeightInput(e, type) {
- // 过滤非数字和非小数点字符(包括负号)
- let value = e.replace(/[^\d.]/g, '');
- // 限制只能有一个小数点
- const dotCount = (value.match(/\./g) || []).length;
- if (dotCount > 1) {
- value = value.slice(0, value.lastIndexOf('.'));
- }
- // 限制不能以小数点开头
- if (value.startsWith('.')) {
- value = '0' + value;
- }
- // 更新绑定值
- this.form[type] = value;
- // this.calculateWeight(type);
- },
- //计算重量
- calculateWeight(type) {
- let total =
- this.form.qualifiedWeight - 0 + (this.form.unqualifiedWeight - 0);
- if (total > this.current.weight) {
- this.form[type] = 0;
- this.$message.warning('合格重量加不合格重量不能大于任务重量');
- }
- },
- // 计算数量:本次报工+本次损耗 不能超过 任务数量 - 已报工 - 已损耗
- calculateQuantity(type) {
- const req = Number(this.current.quantity) || 0;
- const done = this.add(this.reportNum, this.lossNum);
- const remaining = this.sub(req, done);
- const curRep = Number(this.form.reportQuantity) || 0;
- const curLoss = Number(this.form.lossQuantity) || 0;
- const curTotal = this.add(curRep, curLoss);
- if (curTotal > remaining) {
- this.form[type] = '';
- this.$message.warning(
- `本次报工数与损耗数之和不能超过任务剩余可报数量(剩余 ${remaining})`
- );
- }
- },
- getDecimalLength(num) {
- return (num.toString().split('.')[1] || '').length;
- },
- toInteger(num) {
- const len = this.getDecimalLength(num);
- return {
- int: Math.round(num * Math.pow(10, len)),
- factor: Math.pow(10, len)
- };
- },
- add(a, b) {
- const { int: aInt, factor: aFactor } = this.toInteger(a);
- const { int: bInt, factor: bFactor } = this.toInteger(b);
- const maxFactor = Math.max(aFactor, bFactor);
- return (
- (aInt * (maxFactor / aFactor) + bInt * (maxFactor / bFactor)) /
- maxFactor
- );
- },
- sub(a, b) {
- const { int: aInt, factor: aFactor } = this.toInteger(a);
- const { int: bInt, factor: bFactor } = this.toInteger(b);
- const maxFactor = Math.max(aFactor, bFactor);
- return (
- (aInt * (maxFactor / aFactor) - bInt * (maxFactor / bFactor)) /
- maxFactor
- );
- },
- // 数量正则 quantity
- handleQuantityInput(e, type) {
- // 过滤非数字字符(包括负号)
- // let value = e.replace(/[^\d]/g, '');
- // // 限制不能以 0 开头(除非是 0 本身)
- // if (value.startsWith('0') && value.length > 1) {
- // value = value.slice(1);
- // }
- let newVal = e.replace(/[^\d.]/g, '');
- if (newVal.startsWith('.')) {
- newVal = '';
- }
- const firstDotIndex = newVal.indexOf('.');
- if (firstDotIndex !== -1) {
- newVal =
- newVal.slice(0, firstDotIndex + 1) +
- newVal.slice(firstDotIndex + 1).replace(/\./g, '');
- }
- const match = newVal.match(/^(\d+)(\.\d{0,4})?/);
- // this.batchForm.quantity = match ? match[0] : '';
- // 更新绑定值
- this.form[type] = match ? match[0] : '';
- this.calculateQuantity(type);
- },
- submitAdd() {
- this.$refs.form.validate((valid) => {
- if (!valid) return;
- const req = Number(this.current.quantity) || 0;
- const done = this.add(this.reportNum, this.lossNum);
- const remaining = this.sub(req, done);
- const curRep = Number(this.form.reportQuantity) || 0;
- const curLoss = Number(this.form.lossQuantity) || 0;
- const curTotal = this.add(curRep, curLoss);
- if (curTotal > remaining) {
- return this.$message.warning(
- `本次报工数与损耗数之和不能超过任务剩余可报数量(剩余 ${remaining})`
- );
- }
- // if (
- // this.form.qualifiedQuantity -
- // 0 +
- // (this.form.unqualifiedQuantity - 0) !==
- // this.current.quantity
- // ) {
- // return this.$message.warning(
- // `合格数量加不合格数量要等于任务数量${this.current.quantity}`
- // );
- // }
- // if (
- // this.form.qualifiedWeight -
- // 0 +
- // (this.form.unqualifiedWeight - 0) !==
- // this.current.weight
- // ) {
- // return this.$message.warning(
- // `合格重量加不合格重量要等于任务重量${this.current.weight}`
- // );
- // }
- let data = {
- ...this.form,
- apsAssigneeId: this.current.apsAssigneeId
- };
- this.loadingBtn = true;
- batchUpdateRealTime([data])
- .then((res) => {
- this.loadingBtn = false;
- if (res) {
- this.$message.success('操作成功');
- this.cancel();
- this.$emit('success');
- }
- })
- .catch((err) => {
- this.loadingBtn = false;
- this.$message.error(err.message);
- });
- });
- }
- }
- };
- </script>
- <style scoped lang="scss">
- ::v-deep .task-report-dialog {
- overflow: hidden;
- border: 1px solid rgba(40, 120, 210, 0.28);
- border-radius: 6px;
- background: linear-gradient(180deg, #f7fbff 0%, #ffffff 34%, #f4f8fb 100%),
- #fff;
- box-shadow: 0 18px 50px rgba(15, 36, 61, 0.34);
- .el-dialog__header,
- .ele-modal__header {
- position: relative;
- min-height: 54px;
- padding: 0 22px;
- display: flex;
- align-items: center;
- border-bottom: 1px solid rgba(34, 112, 214, 0.22);
- background: linear-gradient(90deg, #102941 0%, #15446d 48%, #0f314e 100%),
- #102941;
- box-shadow: inset 0 -1px 0 rgba(63, 171, 255, 0.38);
- }
- .el-dialog__title,
- .ele-modal__title {
- color: #eef8ff;
- font-size: 17px;
- font-weight: 700;
- letter-spacing: 0;
- }
- .el-dialog__headerbtn,
- .ele-modal__headerbtn {
- top: 17px;
- .el-dialog__close,
- i {
- color: rgba(230, 246, 255, 0.78);
- }
- &:hover {
- .el-dialog__close,
- i {
- color: #40d9ff;
- }
- }
- }
- .el-dialog__body,
- .ele-modal__body {
- padding: 20px 24px 18px;
- background: linear-gradient(
- rgba(36, 122, 206, 0.055) 1px,
- transparent 1px
- ),
- linear-gradient(90deg, rgba(36, 122, 206, 0.045) 1px, transparent 1px),
- linear-gradient(180deg, #f7fbff 0%, #ffffff 46%, #f4f8fb 100%);
- background-size: 28px 28px, 28px 28px, 100% 100%;
- }
- .el-form {
- color: #26384a;
- }
- }
- ::v-deep .task-report-dialog .el-row {
- position: relative;
- }
- ::v-deep .task-report-dialog .basic {
- margin: 12px 0 8px !important;
- padding: 14px 14px 2px;
- border: 1px solid rgba(28, 118, 208, 0.18);
- border-radius: 6px;
- background: rgba(255, 255, 255, 0.78);
- box-shadow: inset 4px 0 0 rgba(35, 148, 255, 0.78),
- 0 8px 20px rgba(24, 58, 92, 0.06);
- }
- ::v-deep .task-report-dialog .el-form > .el-row:first-child {
- margin: 12px 0 8px;
- padding: 14px 14px 8px;
- border: 1px solid rgba(28, 118, 208, 0.22);
- border-radius: 6px;
- background: linear-gradient(
- 180deg,
- rgba(231, 244, 255, 0.88),
- rgba(255, 255, 255, 0.84)
- ),
- #fff;
- box-shadow: inset 4px 0 0 #2394ff, 0 8px 20px rgba(24, 58, 92, 0.08);
- }
- ::v-deep .task-report-dialog .el-form-item {
- margin-bottom: 18px;
- }
- ::v-deep .task-report-dialog .el-form-item__label {
- color: #526170;
- font-size: 14px;
- font-weight: 700;
- }
- ::v-deep .task-report-dialog .el-input__inner,
- ::v-deep .task-report-dialog .el-textarea__inner {
- border-color: #d6e1ec;
- border-radius: 4px;
- background: rgba(255, 255, 255, 0.94);
- color: #23384d;
- font-size: 14px;
- font-weight: 600;
- transition: border-color 0.2s ease, box-shadow 0.2s ease,
- background-color 0.2s ease;
- }
- ::v-deep .task-report-dialog .el-input__inner:hover,
- ::v-deep .task-report-dialog .el-textarea__inner:hover {
- border-color: #8fc8ff;
- }
- ::v-deep .task-report-dialog .el-input__inner:focus,
- ::v-deep .task-report-dialog .el-textarea__inner:focus {
- border-color: #2394ff;
- background: #fff;
- box-shadow: 0 0 0 3px rgba(35, 148, 255, 0.12);
- }
- ::v-deep .task-report-dialog .el-input.is-disabled .el-input__inner,
- ::v-deep .task-report-dialog .el-textarea.is-disabled .el-textarea__inner {
- border-color: #e1e8ef;
- background: #f4f7fa;
- color: #5d6975;
- -webkit-text-fill-color: #5d6975;
- }
- ::v-deep .task-report-dialog .el-input-group__append {
- border-color: #d6e1ec;
- background: #eef4fa;
- color: #657485;
- font-weight: 700;
- }
- ::v-deep
- .task-report-dialog
- .el-form-item.is-required:not(.is-no-asterisk)
- > .el-form-item__label:before {
- color: #ff5a5f;
- font-weight: 800;
- }
- ::v-deep .task-report-dialog .header-title,
- ::v-deep .task-report-dialog .headerTitle,
- ::v-deep .task-report-dialog .header_title {
- margin-top: 22px !important;
- }
- ::v-deep .time_select {
- width: 100%;
- }
- ::v-deep .task-report-dialog .tool_btn {
- margin: 8px 0 18px;
- text-align: right;
- .el-button {
- min-width: 92px;
- padding: 11px 24px !important;
- border-radius: 4px;
- font-size: 15px !important;
- font-weight: 700;
- }
- .el-button--primary {
- border-color: #1d8fff;
- background: linear-gradient(135deg, #1597ff 0%, #006fd6 100%);
- box-shadow: 0 8px 18px rgba(0, 122, 218, 0.28);
- &:hover,
- &:focus {
- border-color: #35b9ff;
- background: linear-gradient(135deg, #35b9ff 0%, #087ee8 100%);
- }
- }
- }
- @media (max-width: 1366px) {
- ::v-deep .task-report-dialog {
- width: 86vw !important;
- }
- }
- @media (max-width: 768px) {
- ::v-deep .task-report-dialog {
- width: 94vw !important;
- .el-dialog__body,
- .ele-modal__body {
- padding: 16px 14px;
- }
- }
- ::v-deep .task-report-dialog .basic,
- ::v-deep .task-report-dialog .el-form > .el-row:first-child {
- padding: 12px 10px 2px;
- }
- }
- </style>
|