| | |
| | | <template> |
| | | <view class="prod-reporting"> |
| | | <PageHeader title="生产报工" /> |
| | | |
| | | <view class="search_form"> |
| | | <u-form> |
| | | <view class="form-row"> |
| | | <u-form-item label="客户名称" label-width="80"> |
| | | <up-input v-model="searchForm.customerName" placeholder="请输入" clearable @change="handleQuery" /> |
| | | </u-form-item> |
| | | </view> |
| | | <view class="form-row"> |
| | | <u-form-item label="状态" label-width="80" style="flex:1"> |
| | | <uni-data-select v-model="searchForm.status" :localdata="statusList"></uni-data-select> |
| | | <!-- <up-input v-model="statusDisplay" placeholder="请选择状态" readonly @click="showStatusPicker = true" /> --> |
| | | </u-form-item> |
| | | </view> |
| | | <view class="form-actions"> |
| | | <u-button type="primary" size="small" @click="handleQuery">搜索</u-button> |
| | | </view> |
| | | </u-form> |
| | | </view> |
| | | |
| | | <view class="list_container"> |
| | | <u-loading-icon v-if="tableLoading" text="加载中..." /> |
| | | <view v-else> |
| | | <view v-if="!tableData || tableData.length === 0" class="empty">暂无数据</view> |
| | | <view v-else class="card_list"> |
| | | <view v-for="item in tableData" :key="item.id" class="card_item"> |
| | | <view class="card_header"> |
| | | <u-tag :type="statusType(item.status)" size="mini">{{ statusText(item.status) }}</u-tag> |
| | | <text class="card_title">{{ item.projectName }}</text> |
| | | </view> |
| | | <view class="card_body"> |
| | | <view class="row"><text class="label">排产日期</text><text class="value">{{ item.schedulingDate }}</text></view> |
| | | <view class="row"><text class="label">排产人</text><text class="value">{{ item.schedulingUserName }}</text></view> |
| | | <view class="row"><text class="label">合同号</text><text class="value">{{ item.salesContractNo }}</text></view> |
| | | <!-- <view class="row"><text class="label">客户合同号</text><text class="value">{{ item.customerContractNo }}</text></view> --> |
| | | <view class="row"><text class="label">客户名称</text><text class="value">{{ item.customerName }}</text></view> |
| | | <view class="row"><text class="label">产品大类</text><text class="value">{{ item.productCategory }}</text></view> |
| | | <view class="row"><text class="label">规格型号</text><text class="value">{{ item.specificationModel }}</text></view> |
| | | <view class="row inline"> |
| | | <view class="col"><text class="label">单位</text><text class="value">{{ item.unit }}</text></view> |
| | | <view class="col"><text class="label">排产数量</text><text class="value">{{ item.schedulingNum }}</text></view> |
| | | <view class="col"><text class="label">生产数量</text><text class="value">{{ item.finishedNum }}</text></view> |
| | | <view class="col"><text class="label">待报工数量</text><text class="value">{{ item.pendingFinishNum }}</text></view> |
| | | </view> |
| | | </view> |
| | | <view class="card_actions"> |
| | | <u-button type="primary" size="small" @click="openForm('add', item)" :disabled="item.pendingFinishNum == 0">生产报工</u-button> |
| | | </view> |
| | | </view> |
| | | </view> |
| | | |
| | | |
| | | <view class="invoice-add"> |
| | | <!-- 使用通用页面头部组件 --> |
| | | <PageHeader title="生产报工" |
| | | @back="goBack" /> |
| | | <!-- 表单内容 --> |
| | | <u-form @submit="submitForm" |
| | | ref="formRef" |
| | | label-width="110" |
| | | input-align="right" |
| | | error-message-align="right"> |
| | | <!-- 基本信息 --> |
| | | <view class="form-section"> |
| | | <u-form-item label="待生产数量" |
| | | prop="planQuantity" |
| | | required> |
| | | <u-input v-model="form.planQuantity" |
| | | placeholder="自动填充" |
| | | disabled /> |
| | | </u-form-item> |
| | | <u-form-item label="本次生产数量" |
| | | prop="quantity" |
| | | required> |
| | | <u-input v-model="form.quantity" |
| | | placeholder="请输入" |
| | | type="number" /> |
| | | <!-- <u-number-box v-model="form.quantity" |
| | | step="0.1" |
| | | bgColor="#fff" |
| | | decimal-length="1" |
| | | :min="0"></u-number-box> --> |
| | | </u-form-item> |
| | | <u-form-item label="班组信息" |
| | | prop="schedulingUserId" |
| | | required> |
| | | <u-input v-model="form.userName" |
| | | placeholder="请选择生产人" |
| | | readonly /> |
| | | </u-form-item> |
| | | </view> |
| | | </view> |
| | | |
| | | <form-dia ref="formDia" @close="handleQuery"></form-dia> |
| | | |
| | | <!-- 状态选择器 --> |
| | | <up-action-sheet :show="showStatusPicker" :actions="statusActions" title="选择状态" @select="onStatusSelect" @close="showStatusPicker = false" /> |
| | | <!-- 使用FooterButtons组件 --> |
| | | <FooterButtons @cancel="goBack" |
| | | @confirm="submitForm" |
| | | :loading="submitting" /> |
| | | <!-- 为底部按钮留出空间 --> |
| | | <view style="height: 80px;"></view> |
| | | </u-form> |
| | | <!-- 生产人选择器 --> |
| | | <up-action-sheet :show="showProducerPicker" |
| | | :actions="producerList" |
| | | title="选择生产人" |
| | | @select="onProducerConfirm" |
| | | @close="showProducerPicker = false" /> |
| | | </view> |
| | | </template> |
| | | |
| | | <script setup> |
| | | import { onMounted, ref, reactive, toRefs, nextTick, computed } from "vue"; |
| | | import PageHeader from '@/components/PageHeader.vue' |
| | | import FormDia from './components/formDia.vue' |
| | | import { workListPage } from "@/api/productionManagement/productionReporting.js"; |
| | | import { ref, onMounted } from "vue"; |
| | | import { onLoad } from "@dcloudio/uni-app"; |
| | | import FooterButtons from "@/components/FooterButtons.vue"; |
| | | import modal from "@/plugins/modal"; |
| | | |
| | | const statusList = reactive([{ |
| | | text:'待报工', |
| | | value: 1 |
| | | },{ |
| | | text:'排产中', |
| | | value: 2 |
| | | }, |
| | | // { |
| | | // text:'生产中', |
| | | // value: 3 |
| | | // }, |
| | | ]) |
| | | const showToast = message => { |
| | | uni.showToast({ |
| | | title: message, |
| | | icon: "none", |
| | | }); |
| | | }; |
| | | import { addProductMain } from "@/api/productionManagement/productionReporting"; |
| | | import { getInfo } from "@/api/login"; |
| | | |
| | | const data = reactive({ |
| | | searchForm: { |
| | | customerName: "", |
| | | projectName: "", |
| | | status: undefined, |
| | | }, |
| | | }); |
| | | const { searchForm } = toRefs(data); |
| | | const showStatusPicker = ref(false) |
| | | const statusOptions = ref([ |
| | | { label: '待报工', value: 1 }, |
| | | { label: '生产中', value: 2 }, |
| | | { label: '已报工', value: 3 }, |
| | | ]) |
| | | const statusActions = computed(() => statusOptions.value.map(o => ({ name: o.label, value: o.value }))) |
| | | const statusDisplay = ref('') |
| | | const tableData = ref([]); |
| | | const tableLoading = ref(false); |
| | | const page = reactive({ |
| | | current: -1, |
| | | size: -1, |
| | | }); |
| | | const formDia = ref() |
| | | // 表单引用 |
| | | const formRef = ref(); |
| | | |
| | | // 查询列表 |
| | | /** 搜索按钮操作 */ |
| | | const handleQuery = () => { |
| | | page.current = -1; |
| | | page.size = -1; |
| | | getList(); |
| | | }; |
| | | const getList = () => { |
| | | tableLoading.value = true; |
| | | const params = { ...searchForm.value, ...page }; |
| | | workListPage(params).then(res => { |
| | | tableLoading.value = false; |
| | | tableData.value = res.data.records.map(item => ({ |
| | | ...item, |
| | | pendingFinishNum: (Number(item.schedulingNum) || 0) - (Number(item.finishedNum) || 0) |
| | | })); |
| | | }).catch(err => { |
| | | tableLoading.value = false; |
| | | }) |
| | | }; |
| | | // 状态选择 |
| | | const onStatusSelect = (item) => { |
| | | searchForm.value.status = item?.value |
| | | statusDisplay.value = item?.name || '' |
| | | showStatusPicker.value = false |
| | | handleQuery() |
| | | } |
| | | // 打开弹框 |
| | | const openForm = (type, row) => { |
| | | if (!row) return |
| | | if ((Number(row.pendingFinishNum) || 0) === 0) { |
| | | uni.showToast({ title: '无需再报工', icon: 'none' }) |
| | | return |
| | | } |
| | | nextTick(() => { formDia.value?.openDialog(type, row) }) |
| | | }; |
| | | // 表单数据 |
| | | let form = ref({ |
| | | planQuantity: 0, |
| | | quantity: 0, |
| | | userName: "", |
| | | workOrderId: "", |
| | | reportWork: "", |
| | | productProcessRouteItemId: "", |
| | | userId: "", |
| | | productMainId: null, |
| | | }); |
| | | let schedulingUserName = ref(""); |
| | | |
| | | // 状态文本/类型 |
| | | const statusText = (s) => { |
| | | if (s == 3) return '已报工' |
| | | if (s == 1) return '待报工' |
| | | return '生产中' |
| | | } |
| | | const statusType = (s) => { |
| | | if (s == 3) return 'success' |
| | | if (s == 1) return 'primary' |
| | | return 'warning' |
| | | } |
| | | // 日期选择器状态 |
| | | const showEnterDatePicker = ref(false); |
| | | const enterDateValue = ref(Date.now()); |
| | | |
| | | // 无分页 |
| | | // 生产人选择器状态 |
| | | const showProducerPicker = ref(false); |
| | | const producerList = ref([]); |
| | | |
| | | // 明细人员/日期选择 |
| | | const openChildUserPicker = (index) => { |
| | | if (!expandData.value[index]?.editType) return |
| | | childUserPicker.value.index = index |
| | | childUserPicker.value.show = true |
| | | } |
| | | const onChildUserSelect = (item) => { |
| | | if (item && childUserPicker.value.index > -1) { |
| | | const row = expandData.value[childUserPicker.value.index] |
| | | row.schedulingUserId = item.value |
| | | row.schedulingUserName = item.name |
| | | } |
| | | childUserPicker.value.show = false |
| | | } |
| | | const openChildDatePicker = (index) => { |
| | | if (!expandData.value[index]?.editType) return |
| | | childDatePicker.value.index = index |
| | | childDatePicker.value.value = Date.now() |
| | | childDatePicker.value.show = true |
| | | } |
| | | const onChildDateConfirm = (e) => { |
| | | const d = new Date(e.value) |
| | | const y = d.getFullYear(); const m = String(d.getMonth()+1).padStart(2, '0'); const day = String(d.getDate()).padStart(2, '0') |
| | | const str = `${y}-${m}-${day}` |
| | | if (childDatePicker.value.index > -1) { |
| | | expandData.value[childDatePicker.value.index].schedulingDate = str |
| | | } |
| | | childDatePicker.value.show = false |
| | | } |
| | | // 生产人选择确认 |
| | | const onProducerConfirm = e => { |
| | | form.value.schedulingUserId = e.value; |
| | | schedulingUserName.value = e.name; |
| | | showProducerPicker.value = false; |
| | | }; |
| | | |
| | | onMounted(() => { |
| | | getList(); |
| | | }); |
| | | // 提交状态 |
| | | const submitting = ref(false); |
| | | |
| | | // 返回上一页 |
| | | const goBack = () => { |
| | | uni.navigateBack(); |
| | | }; |
| | | // 提交表单 |
| | | const submitForm = async () => { |
| | | submitting.value = true; |
| | | // 校验表单 |
| | | if (!form.value.quantity) { |
| | | submitting.value = false; |
| | | showToast("请输入本次生产数量"); |
| | | return; |
| | | } |
| | | if (form.value.quantity > form.value.planQuantity) { |
| | | submitting.value = false; |
| | | showToast("本次生产数量不能大于待生产数量"); |
| | | return; |
| | | } |
| | | console.log(form.value, "form.value"); |
| | | |
| | | addProductMain(form.value).then(res => { |
| | | if (res.code === 200) { |
| | | showToast("报工成功"); |
| | | submitting.value = false; |
| | | setTimeout(() => { |
| | | goBack(); |
| | | }, 1000); |
| | | } else { |
| | | showToast(res.msg || "报工失败"); |
| | | submitting.value = false; |
| | | } |
| | | }); |
| | | }; |
| | | |
| | | // 页面加载时初始化数据 |
| | | onLoad(options => { |
| | | console.log(options, "options"); |
| | | try { |
| | | const orderRow = JSON.parse(options.orderRow); |
| | | console.log(orderRow, "orderRow======########"); |
| | | form.value.planQuantity = orderRow.planQuantity; |
| | | form.value.quantity = orderRow.quantity; |
| | | form.value.productProcessRouteItemId = orderRow.productProcessRouteItemId; |
| | | form.value.workOrderId = orderRow.id; |
| | | form.value.reportWork = orderRow.reportWork; |
| | | form.value.productMainId = orderRow.productMainId; |
| | | getInfo().then(res => { |
| | | form.value.userId = res.user.userId; |
| | | form.value.userName = res.user.userName; |
| | | }); |
| | | } catch (error) { |
| | | modal.msgError("订单解析失败"); |
| | | goBack(); |
| | | return; |
| | | } |
| | | }); |
| | | </script> |
| | | |
| | | <style scoped lang="scss"> |
| | | .prod-reporting { padding-bottom: 12px; } |
| | | .search_form { margin: 12px; background: #fff; border-radius: 8px; padding: 10px; } |
| | | .form-row { display: flex; gap: 12px; } |
| | | .form-actions { display: flex; justify-content: flex-end; } |
| | | .list_container { padding: 0 12px; } |
| | | .empty { text-align: center; color: #888; padding: 20px 0; } |
| | | .card_list { display: flex; flex-direction: column; gap: 10px; } |
| | | .card_item { background: #fff; border-radius: 10px; padding: 10px; box-shadow: 0 2px 8px rgba(0,0,0,0.05); } |
| | | .card_header { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; } |
| | | .card_title { font-weight: 500; color: #333; margin-left: auto; } |
| | | .card_body .row { display: flex; justify-content: space-between; padding: 4px 0; } |
| | | .card_body .row.inline { display: flex; gap: 10px; flex-wrap: wrap; } |
| | | .card_body .row.inline .col { min-width: 45%; display: flex; justify-content: space-between; } |
| | | .label { color: #666; font-size: 12px; } |
| | | .value { color: #333; font-size: 12px; } |
| | | .card_actions { display: flex; justify-content: flex-end; gap: 8px; padding-top: 8px; } |
| | | .ml8 { margin-left: 8px; } |
| | | |
| | | @import "@/static/scss/form-common.scss"; |
| | | </style> |
| | | |
| | | |