material_pre_request.vue 13.9 KB
<!--
 * @Date: 2024-07-23 12:53:15
 * @LastEditors: hookehuyr hookehuyr@gmail.com
 * @LastEditTime: 2024-07-25 13:21:17
 * @FilePath: /temple_material_request/src/views/material_pre_request.vue
 * @Description: 待申领物资页面
-->
<template>
  <div class="material-pre-request-page">
    <div class="list-wrapper">
      <van-sticky>
        <van-row justify="space-between" class="select-all-item">
          <van-col span="8">
            <!-- TODO:编辑模式下,不能确认申请 -->
            <span v-if="model === 'edit'">
              <van-icon v-if="is_all_checked" @click="onCheckAll()" name="checked" size="1.25rem" :color="styleColor.baseColor" />
              <van-icon v-else name="passed" @click="onCheckAll()" size="1.25rem" />
              <span @click="onCheckAll()" :style="{ color: styleColor.baseColor }">&nbsp;&nbsp;全选</span>
            </span>
            <!-- TODO:非编辑模式下,显示购物车总数量 -->
            <span v-else :style="{ color: styleColor.baseColor }">品项数: {{ sum_num }}</span>
          </van-col>
          <van-col span="16" :style="{ textAlign: 'right', fontSize: '0.85rem', color: styleColor.baseColor }">
            <span v-if="model !== 'edit'" @click="onClickEdit"><van-icon name="records-o" />&nbsp;编辑</span>
            <span v-else>
              <span @click="onClickDel"><van-icon name="delete-o" />&nbsp;删除</span>&nbsp;&nbsp;
              <span @click="onClickCancel"><van-icon name="close" />&nbsp;取消编辑</span>
            </span>
          </van-col>
        </van-row>
      </van-sticky>
      <div v-for="item in list" :id="item.id" :key="item" class="list-boxer">
        <van-row align="center" justify="space-between">
          <van-col span="16" style="display: flex;">
            <span v-if="item.edit">
              <van-icon v-if="item.checked" @click="onCheck(item)" name="checked" size="1.25rem" :color="styleColor.baseColor" />
              <van-icon v-else name="passed" @click="onCheck(item)" size="1.25rem" />&nbsp;&nbsp;
            </span>
            <div class="van-ellipsis" :style="{ color: styleColor.baseColor, textDecoration: 'underline' }" @click="onClickTitle(item)">
              {{ item.name }}
            </div>
          </van-col>
          <van-col span="8" style="display: flex; align-items: center;">
            <van-field
              v-model="item.num"
              style="border: 1px solid #f0f0f0; padding: 0; border-radius: 5px;"
              label=""
              label-width="0"
              input-align="center"
              placeholder="数量"
              type="number"
              :disabled="!item.edit"
              @blur="onBlur(item)"
            >
              <template #left-icon></template>
            </van-field>&nbsp;&nbsp;<span style="font-size: 0.9rem; color: #666;">个</span>
          </van-col>
        </van-row>
        <div v-if="item.error" style="padding: 0.5rem 2rem 0 0; font-size: 0.85rem; color: red; text-align: right;">输入值有误</div>
      </div>
      <div style="height: 6rem;"></div>
      <div style="position: fixed; left: 0; right: 0; bottom:4.5rem; padding: 1rem;">
        <van-button icon="plus" type="primary" :color="styleColor.baseColor" plain block @click="addMore">添加更多</van-button>
      </div>
    </div>
    <div class="control-bar">
      <!--  -->
      <div style="display: flex; justify-content: space-between; align-items: center;">
        <div style="display: flex; align-items: center;" @click="showPicker = true">
          <div style="font-size: 0.85rem; color: #202020;">使用时间:</div>&nbsp;&nbsp;
          <div style="border: 1px solid #f0f0f0; border-radius: 5px; padding: 0.5rem 0.35rem 0.5rem 1rem; min-width: 6rem; font-size: 0.85rem; display: flex; align-items: center; justify-content: space-between;">{{ use_date }}&nbsp;&nbsp;<van-icon name="notes-o" size="1rem" :color="styleColor.baseColor"  /></div>
        </div>
        <div style="display: flex; align-items: center;">
          <van-button type="primary" :color="styleColor.baseColor" @click="onConfirmRequest">确定申领</van-button>
        </div>
      </div>
    </div>
  </div>

  <van-popup v-model:show="showPicker" position="bottom">
    <van-date-picker
      v-model="currentDate"
      title="日期选择"
      :min-date="minDate"
      :max-date="maxDate"
      :columns-type="columns_type"
      @confirm="onConfirm"
      @cancel="showPicker = false"
    />
  </van-popup>

  <van-dialog v-model:show="showType" title="" :show-cancel-button="false" :show-confirm-button="false">
    <div style="padding: 1.5rem 0 0; text-align: center; font-size: 0.95rem; font-weight: bold;">请确认您本次是为哪个组别申领物资</div>
    <div style="display: flex; align-items: center; padding: 1rem;">
      <!-- <div style="font-size: 0.9rem; margin-right: 1rem; width: 5rem;">申领组:&nbsp;&nbsp;</div> -->
      <div>
        <van-radio-group v-model="type_checked" direction="horizontal" style="font-size: 0.9rem;">
          <van-radio name="1" :checked-color="styleColor.baseColor" style="margin-bottom: 0.25rem;">单选框 1</van-radio>
          <van-radio name="2" :checked-color="styleColor.baseColor" style="margin-bottom: 0.25rem;">单选框 2</van-radio>
          <van-radio name="3" :checked-color="styleColor.baseColor" style="margin-bottom: 0.25rem;">单选框 3</van-radio>
        </van-radio-group>
      </div>
    </div>
    <div style="padding: 0 1rem;">
      <van-row gutter="10" align="center" style="margin-bottom: 0.5rem;">
        <van-col span="7" style="text-align: right;"><span style="color: red;">*</span>申领人:</van-col>
        <van-col span="17"><van-field v-model="request_user" label="" placeholder="请输入" style="border: 1px solid #DBDBDB; padding: 0.25rem 1rem; border-radius: 5px;" /></van-col>
      </van-row>
      <van-row gutter="10" align="center" style="margin-bottom: 1rem;">
        <van-col span="7" style="text-align: right;"><span style="color: red;">*</span>联系电话:</van-col>
        <van-col span="17"><van-field v-model="request_tel" label="" placeholder="请输入" type="number" style="border: 1px solid #DBDBDB; padding: 0.25rem 1rem; border-radius: 5px;" /></van-col>
      </van-row>
    </div>
    <van-row gutter="20" justify="space-around" align="center" style="padding: 1rem; border-top: 1px solid #E9E9E9; text-align: center;">
      <van-col span="12">
        <van-button plain block color="#A67939" @click="onDialogCancel">取消</van-button>
      </van-col>
      <van-col span="12">
        <van-button block color="#A67939" @click="onDialogConfirm">确定</van-button>
      </van-col>
    </van-row>
  </van-dialog>

  <choose-material :show="show_choose_material" @close="onCloseChoose"></choose-material>
  <material-detail :show="show_material_detail" @close="onCloseDetail"></material-detail>

</template>

<script setup>
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { showToast, showConfirmDialog } from 'vant';
import { Cookies, $, _, axios, storeToRefs, mainStore, Toast, useTitle } from '@/utils/generatePackage.js'
//import { } from '@/utils/generateModules.js'
//import { } from '@/utils/generateIcons.js'
//import { } from '@/composables'
import { styleColor } from "@/constant.js";
import dayjs from "dayjs";
import chooseMaterial from '@/components/chooseMaterial/index.vue';
import materialDetail from '@/components/materialDetail/index.vue';

const $route = useRoute();
const $router = useRouter();
useTitle($route.meta.title);

const is_all_checked = ref(false);

const sum_num = ref(999); // TODO: 品项的总数量,需要接口提供
const model = ref(''); // 默认非编辑模式

const onClickEdit = () => { // 点击编辑
  model.value = 'edit';
  list.value.forEach(item => {
    item.checked = false;
    item.error = false;
    item.edit = true;
  })
}
const onClickDel = () => { // 点击删除
  let shop_cart_list = [];
  // 把选中的值集合
  list.value
  .filter(item => item.checked)
  .forEach(item => {
    shop_cart_list = shop_cart_list.concat(item);
  });
  // 购物车为空提示
  if (!shop_cart_list.length) {
    showToast('删除项为空');
    return;
  }
  // TODO:删除选中的项,接口需要一个购物车删除指定ID的接口
  let del_ids = shop_cart_list.map(item => item.id);
  console.warn(del_ids);
  showConfirmDialog({
    title: '温馨提示',
    message:
      `您是否需要删除这 ${del_ids.length} 项物资?`,
      confirmButtonColor: styleColor.baseColor,
  })
    .then(() => {
      // on confirm
      // 还原列表显示
      onClickCancel();
      // TODO: 刷新列表
    })
    .catch(() => {
      // on cancel
    });
}

const onClickCancel = () => { // 点击取消
  if (checkShoppingCart()) {
    model.value = '';
    is_all_checked.value = false;
    list.value.forEach(item => {
      item.error = false;
      item.edit = false;
    });
  }
}

const onCheckAll = () => {
  is_all_checked.value = !is_all_checked.value;
  if (is_all_checked.value) {
    list.value.forEach(item => {
      item.checked = true;
    })
  } else {
    list.value.forEach(item => {
      item.checked = false;
      item.error = false;
    })
  }
}

const onCheck = (item) => {
  item.checked = !item.checked;
  // 全部为选中
  let all_checked = list.value.every((item) => item.checked === true);
  if (all_checked) {
    is_all_checked.value = true;
  } else {
    is_all_checked.value = false;
  }
  // 如果取消选中,隐藏错误提示
  if (!item.checked) {
    item.error = false;
  }
}

const onBlur = (item) => { // 输入框失去焦点回调
  if (item.num === null || item.num === '') {
    item.error = true;
  } else {
    item.error = false;
  }
  // TODO: 输入框失去焦点,接口需要一个购物车更新接口
}

const list = ref([]);
const loading = ref(false);
const finished = ref(false);

const onLoad = () => {
  // 异步更新数据
  // setTimeout 仅做示例,真实场景中一般为 ajax 请求
  setTimeout(() => {
    for (let i = 0; i < 10; i++) {
      list.value.push({ id: list.value.length + 1, name: '标题 床垫 1.2m*2m', num: 11, checked: false, error: false, edit: model.value === 'edit' });
    }

    // 加载状态结束
    loading.value = false;

    // 数据全部加载完成
    if (list.value.length >= 40) {
      finished.value = true;
    }
  }, 1000);
  // TODO: 如果查询到的数据大于0,需要取消全选
  is_all_checked.value = false;
};

const onClickTitle = (item) => { // 点击物资标题回调
  console.warn(item);
  show_material_detail.value = true;
}

const showPicker = ref(false);
const currentDate = ref([]);
const columns_type = ref(['year', 'month', 'day']);
const minDate = ref();
const maxDate = ref();
const use_date = ref('');

const onConfirm = ({ selectedValues, selectedOptions }) => {
  use_date.value = selectedValues.join("-");
  showPicker.value = false;
};

onMounted(() => {
  minDate.value = new Date();
  // 测试
  onLoad()
})

const addMore = () => { // 添加更多回调
  console.warn('addMore');
  show_choose_material.value = true;
}

const shop_cart_list = ref([]); // 购物车列表

const checkShoppingCart = () => { // 检查购物车有效性
  let flag = true;
  // 校验购物车值
  let error_list = list.value.filter((item) => { if (item.num === null || item.num === '') { return item;} })
  if (error_list.length) {
    // 跳到第一个错误框
    scrollToSection(error_list[0].id);
    // 标记所有错误
    error_list.forEach(item => {
      item.error = true;
    });
    flag = false
    return;
  }
  return flag;
}

const onConfirmRequest = () => { // 确定申领回调
  console.warn('onConfirmRequest');
  if (!use_date.value) {
    showToast('请选择使用日期');
    return;
  }
  showType.value = true;
}

const scrollToSection = (id) => { // 滚动到指定位置
  const current_index = list.value.findIndex((item) => item.id === id);
  // 因为布局问题,需要滚动到上一个节点 查询上一个节点ID
  const previous_index = current_index - 2 >= 0 ? current_index - 2 : 0;
  nextTick(() => {
    let element = $('.list-wrapper').find(`#${list.value[previous_index]['id']}`);
    if (element[0]) {
      element[0].scrollIntoView({ behavior: 'smooth' });
    } else {
      console.log('Element with ID ' + id + ' not found.');
    }
  })
}

const showType = ref(false);
const type_checked = ref(''); // 组别
const request_user = ref(''); // 申领人
const request_tel = ref(''); // 联系电话
const onDialogConfirm = () => {
  if (!type_checked.value) {
    showToast('请选择组别')
  }
  if (!request_user.value) {
    showToast('申领人不能为空')
  }
  if (!request_tel.value) {
    showToast('联系电话不能为空')
  }
  console.warn('组别', type_checked.value);
  console.warn('use_date', use_date.value);
  console.warn('request_user', request_user.value);
  console.warn('request_tel', request_tel.value);
  // TODO:购物车的值应该不用传,数量应该是单独修改
  showType.value = false;
  // 申领成功跳转
  $router.push({ path: '/success' });
}
const onDialogCancel = () => {
  showType.value = false;
}

const show_choose_material = ref(false);
const onCloseChoose = () => { // 关闭选择物资弹窗回调
  // TODO: 需要刷新列表,应该可能新增的物料
  show_choose_material.value = false;
}

const show_material_detail = ref(false);
const onCloseDetail = () => { // 关闭物资详情窗口
  show_material_detail.value = false;
}
</script>

<style lang="less" scoped>
.material-pre-request-page {
  .list-wrapper {
    position: relative;
    width: 100%;
    .select-all-item {
      padding: 0.5rem 1rem;
      background-color: white;
    }
    .list-boxer {
      margin: 0; padding: 1rem; border-top: 1px solid #f0f0f0;
    }
  }

  .control-bar {
    display: flex; position: fixed; padding: 1rem 1.5rem; left: 0; right: 0; bottom: 0; background-color: white; width: calc(100% - 3rem);  box-shadow: 0rem -0.33rem 0.33rem 0.08rem rgba(0,0,0,0.06); display: flex; flex-direction: column;
  }
}

:deep(.van-picker__confirm) {
  color: #A67939;
}
</style>