zhangwencui
2026-04-30 3fa1df3286670f5480fc1eca31ef81d30b6865f5
src/pages/productionManagement/productionDispatching/components/DispatchModal.vue
@@ -1,399 +1,379 @@
<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>
  <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";
  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 { proxy } = getCurrentInstance();
  const userStore = useUserStore();
  const emit = defineEmits(["confirm"]);
// 弹窗显示状态
const show = ref(false);
const submitting = ref(false);
  // 弹窗显示状态
  const show = ref(false);
  const submitting = ref(false);
// 选择器显示状态
const showUserPicker = ref(false);
const showDatePicker = 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 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 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 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 rules = reactive({
    schedulingNum: [
      { required: true, message: "请输入排产数量", trigger: "blur" },
    ],
    schedulingUserId: [
      { required: true, message: "请选择派工人", trigger: "change" },
    ],
    schedulingDate: [
      { required: true, message: "请选择派工日期", trigger: "change" },
    ],
  });
// 表单引用
const formRef = ref();
  // 表单引用
  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 open = async rowData => {
    try {
      // 加载用户列表
      const res = await userListNoPageByTenantId();
      userList.value = res.data || [];
// 处理数量变化
const handleNumChange = (value) => {
   if (value > form.pendingQuantity) {
      form.schedulingNum = form.pendingQuantity;
      uni.showToast({
         title: '排产数量不可大于待排产数量',
         icon: 'none'
      });
   }
};
      // 填充表单数据
      Object.assign(form, {
        ...rowData,
        schedulingNum: 0,
        schedulingUserId: userStore.id,
        schedulingDate: dayjs().format("YYYY-MM-DD"),
      });
// 处理用户选择
const handleUserSelect = (params) => {
   if (params.value && params.value.length > 0) {
      form.schedulingUserId = params.value[0];
   }
   showUserPicker.value = false;
};
      show.value = true;
    } catch (error) {
      uni.showToast({
        title: "加载用户列表失败",
        icon: "error",
      });
    }
  };
// 处理日期选择
const handleDateSelect = (params) => {
   if (params.value) {
      form.schedulingDate = dayjs(params.value).format("YYYY-MM-DD");
   }
   showDatePicker.value = false;
};
  // 处理数量变化
  const handleNumChange = value => {
    if (value > form.pendingQuantity) {
      form.schedulingNum = form.pendingQuantity;
      uni.showToast({
        title: "排产数量不可大于待排产数量",
        icon: "none",
      });
    }
  };
// 确认派工
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 handleUserSelect = params => {
    if (params.value && params.value.length > 0) {
      form.schedulingUserId = params.value[0];
    }
    showUserPicker.value = false;
  };
// 弹窗打开事件
const handleOpen = () => {
   // 弹窗打开时的处理
};
  // 处理日期选择
  const handleDateSelect = params => {
    if (params.value) {
      form.schedulingDate = dayjs(params.value).format("YYYY-MM-DD");
    }
    showDatePicker.value = false;
  };
// 关闭弹窗
const handleClose = () => {
   show.value = false;
   showUserPicker.value = false;
   showDatePicker.value = false;
   // 重置表单
   Object.assign(form, {
      projectName: "",
      productCategory: "",
      quantity: "",
      schedulingNum: 0,
      schedulingUserId: "",
      schedulingDate: "",
      pendingQuantity: 0,
      id: ""
   });
};
  // 确认派工
  const handleConfirm = async () => {
    try {
      // 表单验证
      const valid = await formRef.value?.validate();
      if (!valid) return;
// 暴露方法
defineExpose({
   open
});
      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;
}
  .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-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;
}
  .modal-title {
    font-size: 18px;
    font-weight: 600;
    color: #333;
  }
.close-btn {
   padding: 4px;
   &:active {
      opacity: 0.7;
   }
}
  .close-btn {
    padding: 4px;
.modal-content {
   flex: 1;
   padding: 0 20px;
   overflow-y: auto;
}
    &:active {
      opacity: 0.7;
    }
  }
.form-section {
   margin-bottom: 24px;
}
  .modal-content {
    flex: 1;
    padding: 0 20px;
    overflow-y: auto;
  }
.section-title {
   display: block;
   font-size: 16px;
   font-weight: 600;
   color: #333;
   margin-bottom: 16px;
   padding-left: 8px;
   border-left: 3px solid #2979ff;
}
  .form-section {
    margin-bottom: 24px;
  }
.modal-footer {
   display: flex;
   gap: 12px;
   padding: 20px;
   border-top: 1px solid #f0f0f0;
   background: #fafafa;
}
  .section-title {
    display: block;
    font-size: 16px;
    font-weight: 600;
    color: #333;
    margin-bottom: 16px;
    padding-left: 8px;
    border-left: 3px solid #2979ff;
  }
// uView 组件样式调整
:deep(.up-form-item) {
   margin-bottom: 20px;
}
  .modal-footer {
    display: flex;
    gap: 12px;
    padding: 20px;
    border-top: 1px solid #f0f0f0;
    background: #fafafa;
  }
:deep(.up-input) {
   background: #f8f9fa;
   border-radius: 8px;
}
  // uView 组件样式调整
  :deep(.up-form-item) {
    margin-bottom: 20px;
  }
:deep(.up-input--disabled) {
   background: #f0f0f0;
   color: #999;
}
  :deep(.up-input) {
    background: #f8f9fa;
    border-radius: 8px;
  }
:deep(.up-number-box) {
   background: #f8f9fa;
   border-radius: 8px;
}
  :deep(.up-input--disabled) {
    background: #f0f0f0;
    color: #999;
  }
  :deep(.up-number-box) {
    background: #f8f9fa;
    border-radius: 8px;
  }
</style>