distribution-order.vue 11.6 KB
<template>
  <view class="page-container">
    <view class="work-order-form-content commonPageLRpadding">
      <up-form
          label-position="left"
          :model="workOrderForm"
          ref="workOrderFormRef"
          labelWidth="190rpx"
      >
        <!-- ========== 工单信息(设计稿 .card) ========== -->
        <view class="form-card form-card--info">
          <view class="sec-head">
            <view class="sec-bar"></view>
            <view class="sec-title">工单信息</view>
          </view>

          <!-- 1. 工单编号(从URL获取展示) -->
          <up-form-item
              label="工单编号"
              border-bottom
          >
            <up-input
                v-model="workOrderForm.orderNo"
                border="none"
                readonly
                placeholder="暂无工单编号"
            ></up-input>
          </up-form-item>

          <!-- 2. 养护员选择(必选,下拉框) -->
          <up-form-item
              label="养护员"
              prop="assigneeName"
              required
              @click="handleActionSheetOpen('assignee'); hideKeyboard()"
          >
            <up-input
                v-model="workOrderForm.assigneeName"
                disabled
                disabled-color="#ffffff"
                placeholder="请选择养护员"
                border="none"
            ></up-input>
            <template #right>
              <up-icon name="arrow-right" size="16" color="#9CA3AF"></up-icon>
            </template>
          </up-form-item>
        </view>

        <!-- ========== 分配说明(设计稿 .card) ========== -->
        <view class="form-card">
          <view class="sec-head">
            <view class="sec-bar"></view>
            <view class="sec-title">分配说明</view>
          </view>

          <!-- 3. 分配说明(非必填,文本域) -->
          <up-form-item
              prop="reason"
          >
            <up-textarea
                placeholder="请输入分配说明"
                v-model.trim="workOrderForm.reason"
                count
                maxlength="200"
                rows="4"
            ></up-textarea>
          </up-form-item>
        </view>
      </up-form>
    </view>

    <!-- 底部提交按钮 -->
    <view class="fixed-bottom-btn-wrap">
      <up-button
          type="primary"
          text="确认分配"
          @click="submitWorkOrder"
      ></up-button>
    </view>

    <!-- 养护员下拉弹窗 -->
    <up-action-sheet
        :show="showActionSheet"
        :actions="currentActionSheetData.list"
        :title="currentActionSheetData.title"
        @close="handleActionSheetClose"
        @select="handleActionSheetSelect"
    ></up-action-sheet>
  </view>
</template>

<script setup>
import { ref, reactive } from 'vue'
import { onLoad, onReady, onShow } from '@dcloudio/uni-app';
import { getYlWorkersPage, universalApproval } from '@/api/work-order-manage/work-order-manage'
import { nextStepMap } from '@/common/utils/common'
import { useUserStore } from '@/pinia/user';
const userStore = useUserStore();
// ========== 表单Ref ==========
const workOrderFormRef = ref(null)
// ========== 页面状态 ==========
const showActionSheet = ref(false)
const currentActionSheetData = reactive({
  type: '',
  list: [],
  title: ''
})
// ========== 下拉列表数据 ==========
const assigneeList = ref([]) // 养护员列表
// ========== 工单表单数据(仅保留所需字段) ==========
const workOrderForm = reactive({
  id:'',
  busiLine:'',
  taskId:'',
  orderNo: '',        // 工单编号(对应接口参数id)
  assigneeId: '',     // 养护员ID(对应接口参数nextAssignee)
  assigneeName: '',   // 养护员名称(显示用)
  reason: ''          // 处理意见(对应接口参数reason)
})
// ========== 表单校验规则(仅保留养护员必选校验) ==========
const workOrderFormRules = reactive({
  assigneeName: [
    {type: 'string', required: true, message: '请选择养护员', trigger: ['change']}
  ],
  reason: [
    {type: 'string', max: 200, message: '处理意见最多200字', trigger: ['change', 'blur']}
  ]
})
// ========== 生命周期 ==========
// onLoad - 获取URL中的工单编号
onLoad((options) => {
  // 从URL参数中获取工单编号(参数名orderNo可根据实际修改)
  if (options && options.orderNo) {
    workOrderForm.orderNo = options.orderNo
    workOrderForm.taskId = options.taskId
    workOrderForm.id = options.id
    workOrderForm.busiLine = options.busiLine


  }
  console.log('从URL获取工单编号:', workOrderForm.orderNo)
})
onReady(() => {
  // 设置表单校验规则
  if (workOrderFormRef.value) {
    workOrderFormRef.value.setRules(workOrderFormRules)
  }
})
onShow(() => {
  // 加载养护员列表
  loadAssigneeList()
})
// ========== 加载养护员列表 ==========
const loadAssigneeList = async () => {
  try {
    uni.showLoading({title: '获取养护员中...'})
    // 调用getYlWorkersPage接口(可根据接口要求传递参数,此处默认空对象)
    console.log(userStore.userInfo.user.busiLine)
    let queryData = {
      // roleCode:userStore.userInfo.roles,
      // roleCode: 'yl_worker',
      busiLine:  workOrderForm.busiLine,
      // busiLine: userStore.userInfo.user.busiLine,
      pageNo: 1,
      pageSize: 100
    }
    const res = await getYlWorkersPage(queryData)
    uni.hideLoading()
    if (res.list.length > 0) {
      assigneeList.value = res.list.map(item => ({
        name: item.nickname,
        value: item.id,
        id: item.id
      }))
      console.log(currentActionSheetData.list)
    } else {
      uni.showToast({title: '所在班组暂无养护员,请先配置养护员', icon: 'none'})
    }
    console.log(currentActionSheetData.list)
  } catch (err) {
    uni.hideLoading()
    console.error('获取养护员列表失败:', err)
    uni.showToast({title: '获取养护员失败,请重试', icon: 'none'})
    assigneeList.value = []
  }
}
// ========== 方法定义 ==========
/**
 * 打开养护员下拉弹窗
 */
const handleActionSheetOpen = (type) => {
  // 判断养护员列表是否为空
  if (type === 'assignee' && assigneeList.value.length === 0) {
    uni.showToast({title: '暂无养护员数据可选', icon: 'none'})
    return
  }
  // 配置弹窗参数
  const configMap = {
    assignee: {
      title: '请选择养护员',
      list: assigneeList.value
    }
  }
  currentActionSheetData.type = type
  currentActionSheetData.title = configMap[type].title
  currentActionSheetData.list = configMap[type].list
  showActionSheet.value = true
}
/**
 * 关闭下拉弹窗
 */
const handleActionSheetClose = () => {
  showActionSheet.value = false
  currentActionSheetData.type = ''
  currentActionSheetData.list = []
  currentActionSheetData.title = ''
}
/**
 * 养护员选择事件
 */
const handleActionSheetSelect = (e) => {
  const {type} = currentActionSheetData
  if (type === 'assignee') {
    workOrderForm.assigneeName = e.name
    workOrderForm.assigneeId = e.value // 绑定养护员ID
    workOrderFormRef.value?.validateField('assigneeName')
  }
  showActionSheet.value = false
}
/**
 * 隐藏键盘
 */
const hideKeyboard = () => {
  uni.hideKeyboard()
}
/**
 * 提交数据(使用ylTeamLeaderAssignWOrder接口,传递指定参数)
 */
const submitWorkOrder = async () => {
  try {
    // 1. 表单校验(先校验养护员必选项)
    await workOrderFormRef.value.validate()
    // 2. 校验工单编号是否存在(避免无工单编号提交)
    if (!workOrderForm.orderNo) {
      uni.showToast({title: '工单编号不能为空', icon: 'none'})
      return
    }
    // 3. 构造接口所需参数
    const submitData = {
      workerDataId:workOrderForm.id,
      operateType: nextStepMap['ylTeamLeader'].operateTypePass,
      taskKey:'ylTeamLeader',
      agree:0,
      taskId: workOrderForm.taskId,        // 工单编码(对应接口参数id)
      reason: workOrderForm.reason.trim(), // 处理建议(对应接口参数reason)
      nextAssignee: workOrderForm.assigneeId // 养护员ID(对应接口参数nextAssignee)
    }
    console.log('提交参数:', submitData)
    // 4. 显示加载提示
    uni.showLoading({title: '提交中...'})
    // 5. 调用指定接口 ylTeamLeaderAssignWOrder
    const res = await universalApproval(submitData)
    // 6. 隐藏加载提示并给出成功反馈
    uni.hideLoading()
    uni.showToast({
      title: '提交成功',
      icon: 'success',
      duration: 1000
    })
    // ========== 核心修改:触发全局刷新事件 ==========
    uni.$emit('refreshWorkOrderList'); // 触发全局自定义事件
    // 7. 提交成功后返回上一页
    setTimeout(() => {
      uni.navigateTo({
        url: `/pages-sub/problem/work-order-manage/index`
      })
    }, 1000)
  } catch (error) {
    // 隐藏加载提示
    uni.hideLoading()
    // 区分表单校验失败和接口调用失败
    if (!Array.isArray(error)) {
      console.error('提交失败:', error)
      uni.showToast({
        title: '提交失败,请重试',
        icon: 'none',
        duration: 2000
      })
    }
  }
}
</script>

<style lang="scss" scoped>
// 页面容器:浅灰底 + 给底部固定栏(按钮 88rpx + 上下各 24rpx)留空间
.page-container {
  min-height: 100vh;
  padding-bottom: calc(180rpx + constant(safe-area-inset-bottom));
  padding-bottom: calc(180rpx + env(safe-area-inset-bottom));
  background-color: #F4F6FA;
}

// 表单内容容器:透明底,左右 24rpx(覆盖全局 commonPageLRpadding 的 15px)
.work-order-form-content {
  padding: 0 24rpx;
  background: transparent;
}

// 白色卡片:8px 圆角 + 卡片阴影(设计稿 .card)
.form-card {
  margin-top: 24rpx;
  padding: 8rpx 24rpx;
  background-color: #ffffff;
  border-radius: 16rpx;
  box-shadow: 0 4rpx 16rpx rgba(17, 24, 39, 0.06);
}

// 区块标题:蓝色竖条 + 标题文字
.sec-head {
  display: flex;
  align-items: center;
  gap: 12rpx;
  padding: 20rpx 0 8rpx;
}

.sec-bar {
  width: 6rpx;
  height: 28rpx;
  background-color: #2563EB;
  border-radius: 3rpx;
}

.sec-title {
  font-size: 30rpx;
  font-weight: 500;
  color: #1F2937;
}

// 表单行:上下 24rpx(左右由卡片内边距控制)
:deep(.u-form-item__body) {
  padding: 24rpx 0 !important;
}

// 工单信息卡片:输入值右对齐
.form-card--info :deep(.u-input__content__field-wrapper__field) {
  text-align: right;
  font-size: 28rpx;
  color: #1F2937;
}

// 分配说明:文本域浅灰底 + 圆角、去掉默认描边(设计稿 .textarea)
.form-card :deep(.u-textarea) {
  border: none;
  background-color: #F4F6FA;
  border-radius: 8rpx;
}

.form-card :deep(.u-textarea__field) {
  font-size: 28rpx;
  color: #1F2937;
}

// 字数统计贴灰底显示(组件内部写死了白底,需 !important 覆盖)
.form-card :deep(.u-textarea__count) {
  background-color: transparent !important;
  color: #9CA3AF;
}

// 底部固定操作栏:白底 + 上分隔线 + 蓝色渐变主按钮(设计稿 .bar / .btn.pri)
.fixed-bottom-btn-wrap {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 10;
  padding: 24rpx 24rpx calc(24rpx + constant(safe-area-inset-bottom));
  padding-bottom: calc(24rpx + env(safe-area-inset-bottom));
  background-color: #ffffff;
  border-top: 1rpx solid #E8EBF0;
  box-shadow: 0 -8rpx 28rpx rgba(17, 24, 39, 0.06);

  :deep(.u-button) {
    height: 88rpx !important;
    border-radius: 16rpx !important;
    border: none !important;
    /* 与顶部导航栏同色 */
    background-color: #2563EB !important;
    background-image: none !important;
  }

  :deep(.u-button__text) {
    font-size: 30rpx !important;
    font-weight: 500 !important;
  }
}


</style>