| src/pages.json | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/pages/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/pages/productionManagement/productionDispatching/components/DispatchModal.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/pages/productionManagement/productionDispatching/components/formDia.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 | |
| src/pages/productionManagement/productionDispatching/index.vue | ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史 |
src/pages.json
@@ -406,6 +406,13 @@ "navigationBarTitleText": "ç产订å", "navigationStyle": "custom" } }, { "path": "pages/productionManagement/productionDispatching/index", "style": { "navigationBarTitleText": "ç产派工", "navigationStyle": "custom" } } ], "subPackages": [ src/pages/index.vue
@@ -124,34 +124,34 @@ </view> <!-- çäº§ç®¡æ§æ¨¡å --> <view class="common-module production-module"> <view class="module-header"> <view class="module-title-container"> <text class="module-title">ç产管æ§</text> </view> </view> <view class="module-content"> <up-grid :border="false" col="4" > <up-grid-item v-for="(item, index) in productionItems" :key="index" @click="handleCommonItemClick(item)" > <view class="icon-container" :style="{ background: item.bgColor }"> <up-icon :name="item.icon" :size="58" color="#ffffff" ></up-icon> </view> <text class="item-label">{{item.label}}</text> </up-grid-item> </up-grid> </view> </view> <!-- <view class="common-module production-module">--> <!-- <view class="module-header">--> <!-- <view class="module-title-container">--> <!-- <text class="module-title">ç产管æ§</text>--> <!-- </view>--> <!-- </view>--> <!-- <view class="module-content">--> <!-- <up-grid--> <!-- :border="false"--> <!-- col="4"--> <!-- >--> <!-- <up-grid-item--> <!-- v-for="(item, index) in productionItems"--> <!-- :key="index"--> <!-- @click="handleCommonItemClick(item)"--> <!-- >--> <!-- <view class="icon-container" :style="{ background: item.bgColor }">--> <!-- <up-icon--> <!-- :name="item.icon"--> <!-- :size="58"--> <!-- color="#ffffff"--> <!-- ></up-icon>--> <!-- </view>--> <!-- <text class="item-label">{{item.label}}</text>--> <!-- </up-grid-item>--> <!-- </up-grid>--> <!-- </view>--> <!-- </view>--> <!-- 设å¤ç®¡ç模å --> <view class="common-module equipment-module"> @@ -433,7 +433,7 @@ break; case 'ç产派工': uni.navigateTo({ url: '/pages/productionManagement/productionDispatch/index' url: '/pages/productionManagement/productionDispatching/index' }); break; case 'å·¥åºæäº§': src/pages/productionManagement/productionDispatching/components/DispatchModal.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,399 @@ <template> <up-popup v-model:show="show" mode="bottom" :round="20" :safeAreaInsetBottom="true" @close="handleClose" @open="handleOpen" > <view class="dispatch-modal"> <!-- å¤´é¨ --> <view class="modal-header"> <text class="modal-title">ç产派工</text> <view class="close-btn" @click="handleClose"> <up-icon name="close" size="20" color="#999"></up-icon> </view> </view> <!-- 表åå 容 --> <view class="modal-content"> <up-form :model="form" ref="formRef" :rules="rules" labelWidth="120" > <!-- 项ç®åºæ¬ä¿¡æ¯ --> <view class="form-section"> <text class="section-title">项ç®ä¿¡æ¯</text> <up-form-item label="项ç®åç§°" prop="projectName"> <up-input v-model="form.projectName" disabled placeholder="项ç®åç§°" /> </up-form-item> <up-form-item label="产å大类" prop="productCategory"> <up-input v-model="form.productCategory" disabled placeholder="产å大类" /> </up-form-item> </view> <!-- æ°éä¿¡æ¯ --> <view class="form-section"> <text class="section-title">æ°éä¿¡æ¯</text> <up-form-item label="æ»æ°é" prop="quantity"> <up-input v-model="form.quantity" disabled placeholder="æ»æ°é" /> </up-form-item> <up-form-item label="å¾ æäº§æ°é" prop="pendingQuantity"> <up-input v-model="form.pendingQuantity" disabled placeholder="å¾ æäº§æ°é" /> </up-form-item> <up-form-item label="æ¬æ¬¡æäº§æ°é" prop="schedulingNum" required> <up-number-box v-model="form.schedulingNum" :min="0" :max="form.pendingQuantity" :step="0.1" :precision="2" @change="handleNumChange" /> </up-form-item> </view> <!-- æ´¾å·¥ä¿¡æ¯ --> <view class="form-section"> <text class="section-title">派工信æ¯</text> <up-form-item label="派工人" prop="schedulingUserId" required> <up-input v-model="selectedUserName" placeholder="è¯·éæ©æ´¾å·¥äºº" readonly @click="showUserPicker = true" suffixIcon="arrow-down" /> </up-form-item> <up-form-item label="æ´¾å·¥æ¥æ" prop="schedulingDate" required> <up-input v-model="form.schedulingDate" placeholder="è¯·éæ©æ´¾å·¥æ¥æ" readonly @click="showDatePicker = true" suffixIcon="calendar" /> </up-form-item> </view> </up-form> </view> <!-- åºé¨æé® --> <view class="modal-footer"> <up-button @click="handleClose" text="åæ¶" type="info" plain :customStyle="{ marginRight: '12px', flex: 1 }" /> <up-button @click="handleConfirm" text="确认派工" type="primary" :customStyle="{ flex: 1 }" :loading="submitting" /> </view> </view> <!-- 人åéæ©å¨ --> <up-picker v-model="showUserPicker" :columns="userColumns" @confirm="handleUserSelect" @cancel="showUserPicker = false" /> <!-- æ¥æéæ©å¨ --> <up-datetime-picker v-model="showDatePicker" mode="date" @confirm="handleDateSelect" @cancel="showDatePicker = false" /> </up-popup> </template> <script setup> import { ref, reactive, computed, getCurrentInstance } from 'vue'; import { userListNoPageByTenantId } from "@/api/system/user.js"; import { productionDispatch } from "@/api/productionManagement/productionOrder.js"; import useUserStore from "@/store/modules/user"; import dayjs from "dayjs"; const { proxy } = getCurrentInstance(); const userStore = useUserStore(); const emit = defineEmits(['confirm']); // å¼¹çªæ¾ç¤ºç¶æ const show = ref(false); const submitting = ref(false); // 鿩卿¾ç¤ºç¶æ const showUserPicker = ref(false); const showDatePicker = ref(false); // ç¨æ·å表 const userList = ref([]); const userColumns = computed(() => [ userList.value.map(user => ({ label: user.nickName, value: user.userId })) ]); // éä¸çç¨æ·åç§°ï¼ç¨äºæ¾ç¤ºï¼ const selectedUserName = computed(() => { const user = userList.value.find(u => u.userId === form.schedulingUserId); return user ? user.nickName : ''; }); // è¡¨åæ°æ® const form = reactive({ projectName: "", productCategory: "", quantity: "", schedulingNum: 0, schedulingUserId: "", schedulingDate: "", pendingQuantity: 0, id: "" // åå§è®°å½ID }); // 表åéªè¯è§å const rules = reactive({ schedulingNum: [ { required: true, message: "请è¾å ¥æäº§æ°é", trigger: "blur" } ], schedulingUserId: [ { required: true, message: "è¯·éæ©æ´¾å·¥äºº", trigger: "change" } ], schedulingDate: [ { required: true, message: "è¯·éæ©æ´¾å·¥æ¥æ", trigger: "change" } ] }); // 表åå¼ç¨ const formRef = ref(); // æå¼å¼¹çª const open = async (rowData) => { try { // å è½½ç¨æ·å表 const res = await userListNoPageByTenantId(); userList.value = res.data || []; // å¡«å è¡¨åæ°æ® Object.assign(form, { ...rowData, schedulingNum: 0, schedulingUserId: userStore.id, schedulingDate: dayjs().format("YYYY-MM-DD") }); show.value = true; } catch (error) { uni.showToast({ title: 'å è½½ç¨æ·å表失败', icon: 'error' }); } }; // å¤çæ°éåå const handleNumChange = (value) => { if (value > form.pendingQuantity) { form.schedulingNum = form.pendingQuantity; uni.showToast({ title: 'æäº§æ°éä¸å¯å¤§äºå¾ æäº§æ°é', icon: 'none' }); } }; // å¤çç¨æ·éæ© const handleUserSelect = (params) => { if (params.value && params.value.length > 0) { form.schedulingUserId = params.value[0]; } showUserPicker.value = false; }; // å¤çæ¥æéæ© const handleDateSelect = (params) => { if (params.value) { form.schedulingDate = dayjs(params.value).format("YYYY-MM-DD"); } showDatePicker.value = false; }; // 确认派工 const handleConfirm = async () => { try { // 表åéªè¯ const valid = await formRef.value?.validate(); if (!valid) return; if (form.schedulingNum <= 0) { uni.showToast({ title: 'æäº§æ°éå¿ é¡»å¤§äº0', icon: 'none' }); return; } submitting.value = true; // æäº¤æ´¾å·¥æ°æ® await productionDispatch(form); uni.showToast({ title: '派工æå', icon: 'success' }); handleClose(); emit('confirm'); } catch (error) { uni.showToast({ title: '派工失败', icon: 'error' }); } finally { submitting.value = false; } }; // å¼¹çªæå¼äºä»¶ const handleOpen = () => { // å¼¹çªæå¼æ¶çå¤ç }; // å ³éå¼¹çª const handleClose = () => { show.value = false; showUserPicker.value = false; showDatePicker.value = false; // é置表å Object.assign(form, { projectName: "", productCategory: "", quantity: "", schedulingNum: 0, schedulingUserId: "", schedulingDate: "", pendingQuantity: 0, id: "" }); }; // æ´é²æ¹æ³ defineExpose({ open }); </script> <style scoped lang="scss"> .dispatch-modal { background: #ffffff; border-radius: 20px 20px 0 0; max-height: 80vh; overflow: hidden; display: flex; flex-direction: column; } .modal-header { display: flex; align-items: center; justify-content: space-between; padding: 20px 20px 0 20px; border-bottom: 1px solid #f0f0f0; padding-bottom: 16px; margin-bottom: 20px; } .modal-title { font-size: 18px; font-weight: 600; color: #333; } .close-btn { padding: 4px; &:active { opacity: 0.7; } } .modal-content { flex: 1; padding: 0 20px; overflow-y: auto; } .form-section { margin-bottom: 24px; } .section-title { display: block; font-size: 16px; font-weight: 600; color: #333; margin-bottom: 16px; padding-left: 8px; border-left: 3px solid #2979ff; } .modal-footer { display: flex; gap: 12px; padding: 20px; border-top: 1px solid #f0f0f0; background: #fafafa; } // uView ç»ä»¶æ ·å¼è°æ´ :deep(.up-form-item) { margin-bottom: 20px; } :deep(.up-input) { background: #f8f9fa; border-radius: 8px; } :deep(.up-input--disabled) { background: #f0f0f0; color: #999; } :deep(.up-number-box) { background: #f8f9fa; border-radius: 8px; } </style> src/pages/productionManagement/productionDispatching/components/formDia.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,169 @@ <template> <div> <el-dialog v-model="dialogFormVisible" title="ç产派工" width="50%" @close="closeDia" > <el-form :model="form" label-width="140px" label-position="top" :rules="rules" ref="formRef"> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="项ç®åç§°ï¼" prop="projectName"> <el-input v-model="form.projectName" placeholder="请è¾å ¥" clearable disabled/> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="产å大类ï¼" prop="productCategory"> <el-input v-model="form.productCategory" placeholder="请è¾å ¥" clearable disabled/> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="æ»æ°éï¼" prop="quantity"> <el-input v-model="form.quantity" placeholder="请è¾å ¥" clearable disabled/> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="å¾ æäº§æ°éï¼" prop="pendingQuantity"> <el-input v-model="form.pendingQuantity" placeholder="请è¾å ¥" clearable disabled/> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="æ¬æ¬¡æäº§æ°éï¼" prop="schedulingNum"> <el-input-number v-model="form.schedulingNum" placeholder="请è¾å ¥" :min="0" :step="0.1" :precision="2" clearable @change="changeNum" style="width: 100%" /> </el-form-item> </el-col> </el-row> <el-row :gutter="30"> <el-col :span="12"> <el-form-item label="派工人ï¼" prop="schedulingUserId"> <el-select v-model="form.schedulingUserId" placeholder="éæ©äººå" style="width: 100%;" > <el-option v-for="user in userList" :key="user.userId" :label="user.nickName" :value="user.userId" /> </el-select> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="æ´¾å·¥æ¥æï¼" prop="schedulingDate"> <el-date-picker v-model="form.schedulingDate" type="date" placeholder="è¯·éæ©æ¥æ" value-format="YYYY-MM-DD" format="YYYY-MM-DD" clearable style="width: 100%" /> </el-form-item> </el-col> </el-row> </el-form> <template #footer> <div class="dialog-footer"> <el-button type="primary" @click="submitForm">确认</el-button> <el-button @click="closeDia">åæ¶</el-button> </div> </template> </el-dialog> </div> </template> <script setup> import {ref} from "vue"; import {getStaffJoinInfo, staffJoinAdd, staffJoinUpdate} from "@/api/personnelManagement/onboarding.js"; import {userListNoPageByTenantId} from "@/api/system/user.js"; import {productionDispatch} from "@/api/productionManagement/productionOrder.js"; import useUserStore from "@/store/modules/user.js"; import dayjs from "dayjs"; const { proxy } = getCurrentInstance() const emit = defineEmits(['close']) const dialogFormVisible = ref(false); const operationType = ref('') const data = reactive({ form: { projectName: "", productCategory: "", quantity: "", schedulingNum: "", schedulingUserId: "", schedulingDate: "", pendingQuantity: "", }, rules: { schedulingNum: [{ required: true, message: "请è¾å ¥", trigger: "blur" },], schedulingUserId: [{ required: true, message: "è¯·éæ©", trigger: "change" },], schedulingDate: [{ required: true, message: "è¯·éæ©", trigger: "change" },], }, }); const { form, rules } = toRefs(data); const userList = ref([]) const userStore = useUserStore() // æå¼å¼¹æ¡ const openDialog = (type, row) => { operationType.value = type; dialogFormVisible.value = true; userListNoPageByTenantId().then((res) => { userList.value = res.data; }); form.value = {...row} form.value.schedulingNum = 0 form.value.schedulingUserId = userStore.id form.value.schedulingDate = dayjs().format("YYYY-MM-DD"); } // const changeNum = (value) => { if (value > form.value.pendingQuantity) { form.value.schedulingNum = form.value.pendingQuantity; proxy.$modal.msgWarning('æäº§æ°éä¸å¯å¤§äºå¾ æäº§æ°é') } } // æäº¤äº§å表å const submitForm = () => { proxy.$refs.formRef.validate(valid => { if (valid) { productionDispatch(form.value).then(res => { proxy.$modal.msgSuccess("æäº¤æå"); closeDia(); }) } }) } // å ³éå¼¹æ¡ const closeDia = () => { proxy.resetForm("formRef"); dialogFormVisible.value = false; emit('close') }; defineExpose({ openDialog, }); </script> <style scoped> </style> src/pages/productionManagement/productionDispatching/index.vue
¶Ô±ÈÐÂÎļþ @@ -0,0 +1,235 @@ <template> <view class="production-dispatching"> <!-- 使ç¨éç¨é¡µé¢å¤´é¨ç»ä»¶ --> <PageHeader title="ç产派工" @back="goBack" /> <!-- æç´¢åºå --> <view class="search-section"> <view class="search-bar"> <view class="search-input"> <up-input class="search-text" placeholder="请è¾å ¥å®¢æ·åç§°æç´¢" v-model="searchForm.customerName" @change="handleQuery" clearable /> </view> <view class="filter-button" @click="handleQuery"> <up-icon name="search" size="24" color="#999"></up-icon> </view> </view> </view> <!-- ç产派工å表 --> <view class="ledger-list" v-if="tableData.length > 0"> <view v-for="(item, index) in tableData" :key="item.id || index"> <view class="ledger-item"> <view class="item-header"> <view class="item-left"> <view class="document-icon"> <up-icon name="file-text" size="16" color="#ffffff"></up-icon> </view> <text class="item-id">{{ item.salesContractNo }}</text> </view> </view> <up-divider></up-divider> <view class="item-details"> <view class="detail-row"> <text class="detail-label">å½å ¥æ¥æ</text> <text class="detail-value">{{ item.entryDate }}</text> </view> <view class="detail-row"> <text class="detail-label">客æ·ååå·</text> <text class="detail-value">{{ item.customerContractNo }}</text> </view> <view class="detail-row"> <text class="detail-label">客æ·åç§°</text> <text class="detail-value">{{ item.customerName }}</text> </view> <view class="detail-row"> <text class="detail-label">项ç®åç§°</text> <text class="detail-value">{{ item.projectName }}</text> </view> <view class="detail-row"> <text class="detail-label">产å大类</text> <text class="detail-value">{{ item.productCategory }}</text> </view> <view class="detail-row"> <text class="detail-label">è§æ ¼åå·</text> <text class="detail-value">{{ item.specificationModel }}</text> </view> <view class="detail-row"> <text class="detail-label">æ»æ°é</text> <text class="detail-value">{{ item.quantity }} {{ item.unit }}</text> </view> <view class="detail-row"> <text class="detail-label">æäº§æ°é</text> <text class="detail-value highlight">{{ item.schedulingNum }}</text> </view> <view class="detail-row"> <text class="detail-label">å¾ ææ°é</text> <text class="detail-value" :class="{ 'danger': item.pendingQuantity <= 0 }">{{ item.pendingQuantity }}</text> </view> </view> <!-- æä½æé®åºå --> <view class="action-buttons"> <up-button type="primary" size="small" @click="handleDispatch(item)" class="action-btn" :disabled="item.pendingQuantity <= 0" > ç产派工 </up-button> </view> </view> </view> </view> <view v-else class="no-data"> <text>ææ çäº§æ´¾å·¥æ°æ®</text> </view> <!-- æ´¾å·¥å¼¹çª --> <DispatchModal ref="dispatchModalRef" @confirm="handleDispatchConfirm" /> </view> </template> <script setup> import { ref, reactive, toRefs, getCurrentInstance } from "vue"; import { onShow } from '@dcloudio/uni-app'; import dayjs from "dayjs"; import {schedulingListPage} from "@/api/productionManagement/productionOrder.js"; import PageHeader from "@/components/PageHeader.vue"; import DispatchModal from "./components/DispatchModal.vue"; const { proxy } = getCurrentInstance(); // å è½½ç¶æ const loading = ref(false); // åè¡¨æ°æ® const tableData = ref([]); // æç´¢è¡¨åæ°æ® const data = reactive({ searchForm: { customerName: "", }, }); const { searchForm } = toRefs(data); // å页é ç½® const page = reactive({ current: -1, size: -1, }); // 派工弹çªå¼ç¨ const dispatchModalRef = ref(); // éç¨æç¤ºå½æ° const showLoadingToast = (message) => { uni.showLoading({ title: message, mask: true }); }; const closeToast = () => { uni.hideLoading(); }; // è¿åä¸ä¸é¡µ const goBack = () => { uni.navigateBack(); }; // æ¥è¯¢å表 const handleQuery = () => { getList(); }; // è·ååè¡¨æ°æ® const getList = () => { loading.value = true; showLoadingToast('å è½½ä¸...'); // æé 请æ±åæ° const params = { ...searchForm.value, ...page }; schedulingListPage(params).then((res) => { loading.value = false; closeToast(); // å¤çæ¯æ¡æ°æ®ï¼å¢å pendingQuantityåæ®µ tableData.value = (res.data.records || []).map(item => ({ ...item, pendingQuantity: (Number(item.quantity) || 0) - (Number(item.schedulingNum) || 0) })); }).catch(() => { loading.value = false; closeToast(); uni.showToast({ title: 'å 载失败', icon: 'error' }); }); }; // å¤ç派工æä½ const handleDispatch = (item) => { if (item.pendingQuantity <= 0) { uni.showToast({ title: 'è¯¥é¡¹ç®æ éåæ´¾å·¥', icon: 'none' }); return; } dispatchModalRef.value?.open(item); }; // å¤ç派工确认 const handleDispatchConfirm = () => { getList(); // å·æ°å表 }; // 页颿¾ç¤ºæ¶å è½½æ°æ® onShow(() => { // å è½½åè¡¨æ°æ® getList(); }); </script> <style scoped lang="scss"> @import '@/styles/sales-common.scss'; // çäº§æ´¾å·¥é¡µé¢æ ·å¼ .production-dispatching { min-height: 100vh; background: #f8f9fa; position: relative; } // åè¡¨é¡¹æ ·å¼ .ledger-item { .detail-value.highlight { color: #ff6b35; font-weight: 600; } .detail-value.danger { color: #ee0a24; font-weight: 600; } } // éé uView ç»ä»¶æ ·å¼ :deep(.up-input) { background: transparent; } </style>