material_request.vue 11.8 KB
<!--
 * @Date: 2024-07-23 12:53:15
 * @LastEditors: hookehuyr hookehuyr@gmail.com
 * @LastEditTime: 2024-07-26 17:34:38
 * @FilePath: /temple_material_request/src/views/material_request.vue
 * @Description: 申领物资页面
-->
<template>
  <div class="material-request-page">
    <van-tabs v-model:active="active" @change="onChange" sticky :color="styleColor.baseColor">
      <van-tab v-for="(item, index) in tabList" :title="item.dept_name" shrink>
        <div class="list-wrapper">
          <van-sticky  :offset-top="44">
            <van-row justify="space-between" class="select-all-item">
              <van-col span="8">
                <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>
              </van-col>
              <van-col span="16" style="text-align: right; font-size: 0.85rem; color: #666666;">参考上次同类活动的领用情况</van-col>
            </van-row>
          </van-sticky>
          <van-list
            v-model:loading="loading"
            :finished="finished"
            finished-text="没有更多了"
            @load="onLoad"
          >
              <div v-for="item in list" :id="item.id" :key="item.id" class="list-boxer">
                <van-row align="center" justify="space-between">
                  <van-col span="16" style="display: flex;">
                    <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;
                    <div class="van-ellipsis" :style="{ color: styleColor.baseColor, textDecoration: 'underline' }" @click="onClickTitle(item)">
                      {{ item.product_name }} / {{ item.spec }}
                    </div>
                  </van-col>
                  <van-col span="8" style="display: flex; align-items: center;">
                    <van-field
                      v-model="item.total_apply_number"
                      style="border: 1px solid #f0f0f0; padding: 0; border-radius: 5px;"
                      label=""
                      label-width="0"
                      input-align="center"
                      placeholder="数量"
                      type="number"
                      @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>
          </van-list>
          <div style="height: 6rem;"></div>
        </div>
      </van-tab>
    </van-tabs>
    <van-empty v-if="!tabList.length" image="error" description="物资情况列表为空" />
    <div class="control-bar">
      <div>
        <van-button icon="plus" type="primary" :color="styleColor.baseColor" @click="addMore">添加更多</van-button>
      </div>
      <div style="display: flex; align-items: center;">
        <van-button plain type="primary" :color="styleColor.baseColor" @click="addShoppingCart">加入购物车</van-button>
        &nbsp;&nbsp;
        <van-badge :content="cart_count">
          <van-icon name="shopping-cart-o" size="2.5rem" :color="styleColor.baseColor" @click="goShoppingCart" />
        </van-badge>
      </div>
    </div>

  </div>

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

</template>

<script setup>
import { ref } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import { showToast, showDialog } 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 chooseMaterial from '@/components/chooseMaterial/index.vue';
import materialDetail from '@/components/materialDetail/index.vue';
import { getActivityDeptsAPI, getGoodUseListAPI, getCartListAPI, addCartAPI } from "@/api/material";

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

const activity_id = $route.query.activity_id ? $route.query.activity_id : 800863;
const form_id = $route.query.form_id ? $route.query.form_id : '';
const client_id = $route.query.client_id ? $route.query.client_id : '';

const cart_count = ref(0); // 购物车数量
const getCartCount = async () => {
  // 购物车数量
  const cartList = await getCartListAPI({activity_id});
  if (cartList.code) {
    cart_count.value = cartList.data.length;
  }
}

onMounted(async () => {
  const { data, code } = await getActivityDeptsAPI({ activity_id, is_previous: 1, only_my_dept: 1 });
  if (code) {
    tabList.value = data;
    if (tabList.value.length) { // 默认选中组别ID
      dept_id.value = tabList.value[0]['dept_id'];
    } else { // 组别为空时跳转到购物车页面
      showDialog({
        title: '温馨提示',
        message: '物资列表为空,将前往添加!',
        confirmButtonColor: styleColor.baseColor
      }).then(() => {
        $router.push({
          path: '/material_pre_request',
          query: {
            activity_id,
            form_id,
            client_id
          }
        })
      });
    }
  }
  // 购物车数量
  getCartCount();
});

const tabList = ref([]); // 组别列表
const dept_id = ref('');

const is_all_checked = ref(false);
const num_value = ref('');

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.checked) {
    // 错误提示
    if (item.total_apply_number === null || item.total_apply_number === '') {
      item.error = true;
    } else {
      item.error = false;
    }
  }
}

const active = ref(0);
const onChange = (index) => { // 切换标签回调
  // 取消全选
  is_all_checked.value = false;
  //
  dept_id.value = tabList.value[index]['dept_id'];
  // 重置查询条件
  limit.value = 20;
  offset.value = 0;
  loading.value = false;
  finished.value = false;
  list.value = [];
}

const list = ref([]);
const loading = ref(false);
const finished = ref(false);
const limit = ref(20);
const offset = ref(0);

const onLoad = async () => {
  // 异步更新数据
  const { code, data } = await getGoodUseListAPI({ activity_id, dept_id: dept_id.value, is_previous: 1, offset: offset.value, limit: limit.value });
  if (code) {
    // 新增选中,错误字段
    data.forEach(item => {
      item.checked = false;
      item.error = false;
    });
    //
    list.value = _.concat(list.value, data);
    list.value = _.uniqBy(list.value, 'good_id');
    offset.value = list.value.length;
    loading.value = false;
    // 数据全部加载完成
    if (!data.length) {
      // 加载状态结束
      finished.value = true;
    }
    // 如果查询到的数据大于0,需要取消全选
    if (data.length) {
      is_all_checked.value = false;
    }
  }
};

const material_id = ref('');
const onClickTitle = (item) => { // 点击物资标题回调
  show_material_detail.value = true;
  material_id.value = item.good_id;
}

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

const shop_cart_list = ref([]); // 购物车列表
const addShoppingCart = async () => { // 加入购物车
  shop_cart_list.value = [];
  // 把选中的值集合
  list.value
  .filter(item => item.checked)
  .forEach(item => {
    shop_cart_list.value = shop_cart_list.value.concat(item);
  });
  // 购物车为空提示
  if (!shop_cart_list.value.length) {
    showToast('请选择物资');
    return;
  }
  // 校验购物车值
  let error_list = shop_cart_list.value.filter((item) => { if (item.total_apply_number === null || item.total_apply_number === '') { return item;} })
  if (error_list.length) {
    // 跳到第一个错误框
    scrollToSection(error_list[0].id);
    // 标记所有错误
    error_list.forEach(item => {
      item.error = true;
    })
    return;
  }
  //
  shop_cart_list.value.forEach(item => {
    item.apply_number = item.total_apply_number;
  });
  // 请求购物车接口
  const { code, data } = await addCartAPI({ activity_id, good_list: shop_cart_list.value });
  if (code) {
    showToast('添加成功');
    setTimeout(() => {
      $router.push({
        path: '/material_pre_request',
        query: {
          activity_id,
          form_id,
          client_id
        }
      });
    }, 1000);
  }
}

const goShoppingCart = () => { // 跳转购物车
  // if (!cart_count.value) {
  //   //
  //   showDialog({
  //     title: '温馨提示',
  //     message:
  //       `您的购物车为空,将前往添加!`,
  //       confirmButtonColor: styleColor.baseColor,
  //   })
  //     .then(() => {
  //       $router.push({
  //         path: '/material_pre_request',
  //         query: {
  //           activity_id,
  //           form_id,
  //           client_id
  //         }
  //       });
  //     })
  //     .catch(() => {
  //       // on cancel
  //     });
  // } else {
  //   $router.push({
  //     path: '/material_pre_request',
  //     query: {
  //       activity_id,
  //       form_id,
  //       client_id
  //     }
  //   });
  // }
  $router.push({
    path: '/material_pre_request',
    query: {
      activity_id,
      form_id,
      client_id
    }
  });
}

const show_choose_material = ref(false);
const onCloseChoose = () => { // 关闭选择物资弹窗回调
  show_choose_material.value = false;
  // 购物车数量
  getCartCount();
}

const show_material_detail = ref(false);
const onCloseDetail = () => {
  show_material_detail.value = false;
}

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.');
    }
  })
}
</script>

<style lang="less" scoped>
.material-request-page {
  .list-wrapper {
    width: 100%;
    .select-all-item {
      padding: 0.5rem 1rem;
      border-top: 1px solid #f0f0f0;
      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); justify-content: space-between; align-items: center; box-shadow: 0rem -0.33rem 0.33rem 0.08rem rgba(0,0,0,0.06);
  }
}
</style>