Toggle navigation
Toggle navigation
This project
Loading...
Sign in
Hooke
/
temple_material_request
Go to a project
Toggle navigation
Toggle navigation pinning
Projects
Groups
Snippets
Help
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Snippets
Network
Create a new issue
Builds
Commits
Issue Boards
Authored by
hookehuyr
2024-07-26 14:46:07 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
6203582522691f32b57cea26685881d9888a99fa
62035825
1 parent
435e5adf
接口和逻辑调整
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
509 additions
and
206 deletions
src/api/material.js
src/components/chooseMaterial/index.vue
src/components/materialDetail/index.vue
src/views/material_list.vue
src/views/material_pre_request.vue
src/views/material_request.vue
src/views/success.vue
src/api/material.js
View file @
6203582
/*
* @Date: 2022-06-17 14:54:29
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-07-2
5 13:13:43
* @LastEditTime: 2024-07-2
6 11:34:18
* @FilePath: /temple_material_request/src/api/material.js
* @Description: 物资申请接口
*/
...
...
@@ -60,6 +60,7 @@ export const addCartAPI = (params) => fn(fetch.post(Api.CART_ADD, params));
/**
* @description: 编辑购物车
* @param: activity_id 活动ID
* @param: good_list [{good_id,apply_number}]
*/
export
const
editCartAPI
=
(
params
)
=>
fn
(
fetch
.
post
(
Api
.
CART_EDIT
,
params
));
...
...
@@ -91,7 +92,7 @@ export const myUserAPI = (params) => fn(fetch.get(Api.MY_USER, params));
* @param: contact_name 领用人姓名
* @param: contact_phone 领用人电话
* @param: use_time 使用时间
* @param: good_list [good_id 物资ID, apply_number 申请数量]
* @param: good_list [good_id 物资ID, apply_number 申请数量]
如果为空,就自动查询购物车中的物资
*/
export
const
addUseOrderAPI
=
(
params
)
=>
fn
(
fetch
.
post
(
Api
.
USE_ORDER_ADD
,
params
));
...
...
@@ -102,10 +103,10 @@ export const addUseOrderAPI = (params) => fn(fetch.post(Api.USE_ORDER_ADD, param
* @param: offset
* @param: limit
*/
export
const
s
kuListAPI
=
(
params
)
=>
fn
(
fetch
.
get
(
Api
.
SKU_LIST
,
params
));
export
const
getS
kuListAPI
=
(
params
)
=>
fn
(
fetch
.
get
(
Api
.
SKU_LIST
,
params
));
/**
* @description: 规格物资详情
* @param: i 规格物资ID
*/
export
const
s
kuInfoAPI
=
(
params
)
=>
fn
(
fetch
.
get
(
Api
.
SKU_INFO
,
params
));
export
const
getS
kuInfoAPI
=
(
params
)
=>
fn
(
fetch
.
get
(
Api
.
SKU_INFO
,
params
));
...
...
src/components/chooseMaterial/index.vue
View file @
6203582
<!--
* @Date: 2024-07-23 16:24:08
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-07-2
5 13:32:12
* @LastEditTime: 2024-07-2
6 13:57:29
* @FilePath: /temple_material_request/src/components/chooseMaterial/index.vue
* @Description: 选择物资组件
-->
<template>
<div class="choose-material-page">
<div
v-if="showBottom"
class="choose-material-page">
<van-popup
v-model:show="showBottom"
position="bottom"
...
...
@@ -20,23 +20,23 @@
<van-row gutter="10" justify="center" align="center">
<van-col span="24">
<div style="background-color: #FBF9F1; display: flex; border-radius: 5rem; padding: 0 1rem; align-items: center; justify-content: center;">
<van-icon name="search" /><van-field v-model="search_value" @blur="onBlur" label="" placeholder="搜索物资" style="background-color: #FBF9F1;" />
<van-icon name="search" /><van-field v-model="search_value" @blur="onBlur" label="" placeholder="搜索物资
名称/规格
" style="background-color: #FBF9F1;" />
</div>
</van-col>
</van-row>
</div>
</div>
<van-row justify="space-around" align="center" style="padding: 1rem; background-color: #F2F2F2;">
<van-col span="8" @click="onCheckAll()">
<van-icon v-if="is_all_checked" name="checked" size="1.25rem" :color="styleColor.baseColor" />
<van-icon v-else name="passed" size="1.25rem" />
<span :style="{ color: styleColor.baseColor }"> 全选</span>
</van-col>
<van-col span="8" style="text-align: center; font-size: 0.95rem; color: #666666; font-weight: bold;">选择物资</van-col>
<van-col span="8"></van-col>
</van-row>
</van-sticky>
<!-- TODO:物资列表显示值需要过滤掉购物车已经选中的物资,新增的物资需要显示在购物车最上面 -->
<van-row justify="space-around" align="center" style="padding: 1rem; background-color: #F2F2F2;">
<van-col span="8" @click="onCheckAll()">
<van-icon v-if="is_all_checked" name="checked" size="1.25rem" :color="styleColor.baseColor" />
<van-icon v-else name="passed" size="1.25rem" />
<span :style="{ color: styleColor.baseColor }"> 全选</span>
</van-col>
<van-col span="8" style="text-align: center; font-size: 0.95rem; color: #666666; font-weight: bold;">选择物资</van-col>
<van-col span="8"></van-col>
</van-row>
<van-list
v-model:loading="loading"
:finished="finished"
...
...
@@ -49,7 +49,7 @@
<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" />
<div class="van-ellipsis" :style="{ color: styleColor.baseColor, textDecoration: 'underline' }" @click="onClickTitle(item)">
{{ item.name }}
{{ item.name }}
/ {{ item.spec }}
</div>
</van-col>
</van-row>
...
...
@@ -68,7 +68,7 @@
</van-popup>
</div>
<material-detail :show="show_material_detail" @close="onCloseDetail"></material-detail>
<material-detail :show="show_material_detail"
:good-id="material_id"
@close="onCloseDetail"></material-detail>
</template>
...
...
@@ -82,11 +82,14 @@ import { Cookies, $, _, axios, storeToRefs, mainStore, Toast, useTitle } from '@
//import { } from '@/composables'
import { styleColor } from "@/constant.js";
import materialDetail from '@/components/materialDetail/index.vue';
import { getSkuListAPI, 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 props = defineProps({
show: Boolean,
});
...
...
@@ -94,46 +97,84 @@ const emit = defineEmits(['close']);
const showBottom = ref(false);
onMounted(() => {
const limit = ref(20);
const offset = ref(0);
const list = ref([]);
const loading = ref(false);
const finished = ref(false);
const getList = async () => {
const { code, data } = await getSkuListAPI({ exclude_activity_id: activity_id, k: '', offset: offset.value, limit: limit.value });
if (code) {
// 默认勾选标记
data.forEach(item => {
item.checked = false;
});
list.value = data;
offset.value = list.value.length;
}
}
onMounted(async () => {
// 获取物资列表
getList();
// 购物车数量
getCartCount();
});
const getCartCount = async () => {
// 购物车数量
const cartList = await getCartListAPI({activity_id});
if (cartList.code) {
cart_count.value = cartList.data.length;
}
}
// 监听字段变化
watch(
() => props.show,
(v) => {
showBottom.value = v;
if (v) {
}
}
);
const onClose = () => {
// 重置查询条件
offset.value = 0;
limit.value = 20;
finished.value = false;
list.value = [];
emit('close');
}
const list = ref([]);
const loading = ref(false);
const finished = ref(false);
const onLoad = () => {
const onLoad = async () => {
// 异步更新数据
// setTimeout 仅做示例,真实场景中一般为 ajax 请求
setTimeout(() => {
for (let i = 0; i < 5; i++) {
list.value.push({ id: i, name: '物资' + i, checked: false });
}
// 加载状态结束
const { code, data } = await getSkuListAPI({ exclude_activity_id: activity_id, k: search_value.value, offset: offset.value, limit: limit.value });
if (code) {
// 默认勾选标记
data.forEach(item => {
item.checked = false;
});
list.value = _.concat(list.value, data);
list.value = _.uniqBy(list.value, 'id');
offset.value = list.value.length;
loading.value = false;
// 数据全部加载完成
if (list.value.length >= 10) {
if (!data.length) {
// 加载状态结束
finished.value = true;
}
}
, 1000);
}
};
const material_id = ref('');
const onClickTitle = (item) => { // 点击物资标题回调
console.warn(item);
show_material_detail.value = true;
material_id.value = item.id;
}
const show_type = ref(false);
...
...
@@ -146,9 +187,22 @@ const onConfirm = () => {
}
const search_value = ref('');
const onBlur = () => {
// TODO: 输入框失去焦点,接口需要一个搜索接口,返回相应的值
console.warn(search_value.value);
const onBlur = async () => { // 搜索回调
// 重置查询条件
offset.value = 0;
limit.value = 20;
finished.value = false;
list.value = [];
// 查询列表数据
const { code, data } = await getSkuListAPI({ exclude_activity_id: activity_id, k: search_value.value, offset: offset.value, limit: limit.value });
if (code) {
// 默认勾选标记
data.forEach(item => {
item.checked = false;
});
list.value = data;
offset.value = list.value.length;
}
}
const show_material_detail = ref(false);
...
...
@@ -181,27 +235,40 @@ const onCheck = (item) => {
}
}
const addShoppingCart = () => { // 新增购物车
const addShoppingCart =
async
() => { // 新增购物车
shop_cart_list.value = [];
list.value.forEach(item => {
item.m_list.forEach(m => {
if (m.checked) {
shop_cart_list.value.push(m);
}
})
if (item.checked) {
shop_cart_list.value.push({
good_id: item.id,
apply_number: 0
});
}
});
// 购物车为空提示
if (!shop_cart_list.value.length) {
showToast('请选择物资');
return;
}
// TODO: 请求购物车接口,更新购物车数量
console.warn(shop_cart_list.value);
// 请求购物车接口,更新购物车数量
const { code, data } = await addCartAPI({ activity_id, good_list: shop_cart_list.value });
if (code) {
// 获取 shop_cart_list 中所有 id 的数组
let idsToRemove = shop_cart_list.value.map(item => item.good_id);
// 过滤 arr1,排除 id 在 idsToRemove 中的元素
list.value = list.value.filter(item => !idsToRemove.includes(item.id));
// 购物车数量
getCartCount();
showToast('添加成功');
}
}
const goShoppingCart = () => { // 点击购物车图标
if ($route.path === '/material_pre_request') { // 待申领物资页面
onClose()
onClose()
;
} else {
$router.push({ path: '/material_pre_request' });
}
...
...
src/components/materialDetail/index.vue
View file @
6203582
<!--
* @Date: 2024-07-23 18:31:35
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-07-2
4 11:00:42
* @LastEditTime: 2024-07-2
6 10:11:43
* @FilePath: /temple_material_request/src/components/materialDetail/index.vue
* @Description: 物资详情页面
-->
<template>
<div class="material-detail-page">
<div
v-if="showRight"
class="material-detail-page">
<van-popup
v-model:show="showRight"
position="right"
...
...
@@ -16,7 +16,7 @@
>
<div style="margin-top: 3rem; background-color: white;">
<div style="display: flex; justify-content: center; align-items: center;">
<div style="padding: 2rem 5rem; padding-bottom: 2rem; border: 1px solid #F2EDE6; background-color: #FFFDF6; text-align: center;">
<div
v-if="!goodInfo.cover"
style="padding: 2rem 5rem; padding-bottom: 2rem; border: 1px solid #F2EDE6; background-color: #FFFDF6; text-align: center;">
<van-image
width="6rem"
height="6rem"
...
...
@@ -25,45 +25,71 @@
/>
<div style="color: #e0d0ba; margin-top: 1rem;">物资图正在整理中</div>
</div>
<div v-else>
<van-image
width="15rem"
height="12rem"
fit="contain"
:src="goodInfo.cover"
/>
</div>
</div>
<div style="text-align: center; font-weight: bold; color: #A67939; font-size: 1.15rem; margin: 1.5rem auto;">
口袋义工服T恤(绿)
</div>
<div style="text-align: center; font-weight: bold; color: #A67939; font-size: 1.15rem; margin: 1.5rem auto;">
{{ goodInfo.name }}
</div>
<div style="color: #1C1C1C; background-color: #F2F2F2; font-size: 1rem; font-weight: bold; padding: 0.5rem 1.5rem;">基本信息</div>
<div style="padding: 1rem;">
<van-row style="margin-bottom: 0.5rem;">
<van-col span="8" style="color: #AFAFAF;">编码</van-col>
<van-col span="16">
XFZ0021004
</van-col>
<van-col span="16">
{{ goodInfo.coding }}
</van-col>
</van-row>
<van-row style="margin-bottom: 0.5rem;">
<van-col span="8" style="color: #AFAFAF;">规格</van-col>
<van-col span="16">
XXL
</van-col>
<van-col span="16">
{{ goodInfo.spec }}
</van-col>
</van-row>
<van-row style="margin-bottom: 0.5rem;">
<van-col span="8" style="color: #AFAFAF;">单位</van-col>
<van-col span="16">
件
</van-col>
<van-col span="16">
{{ goodInfo.specification }}
</van-col>
</van-row>
<van-row style="margin-bottom: 0.5rem;">
<van-col span="8" style="color: #AFAFAF;">分类</van-col>
<van-col span="16">新服装</van-col>
<van-col span="16">
<div v-if="goodInfo.category_name">{{ goodInfo.category_name }}</div>
<div v-else>/</div>
</van-col>
</van-row>
<van-row style="margin-bottom: 0.5rem;">
<van-col span="8" style="color: #AFAFAF;">描述</van-col>
<van-col span="16">/</van-col>
<van-col span="16">
<div v-if="goodInfo.description" v-html="goodInfo.description"></div>
<div v-else>/</div>
</van-col>
</van-row>
<van-row style="margin-bottom: 0.5rem;">
<van-col span="8" style="color: #AFAFAF;">条码</van-col>
<van-col span="16">/</van-col>
<van-col span="16">
<div v-if="goodInfo.bar_code">{{ goodInfo.bar_code }}</div>
<div v-else>/</div>
</van-col>
</van-row>
<van-row style="margin-bottom: 0.5rem;">
<van-col span="8" style="color: #AFAFAF;">价格</van-col>
<van-col span="16">/</van-col>
<van-col span="16">
<div v-if="goodInfo.price">{{ goodInfo.price }}</div>
<div v-else>/</div>
</van-col>
</van-row>
<van-row style="margin-bottom: 0.5rem;">
<van-col span="8" style="color: #AFAFAF;">是否可定</van-col>
<van-col span="16">可定</van-col>
<van-col span="16">
<div v-if="goodInfo.is_ordered">可定</div>
<div v-else>不可定</div>
</van-col>
</van-row>
<van-row style="margin-bottom: 0.5rem;">
<van-col span="8" style="color: #AFAFAF;">状态</van-col>
<van-col span="16">上架</van-col>
<van-col span="16">
<div v-if="goodInfo.status === 9">上架</div>
<div v-else>下架</div>
</van-col>
</van-row>
</div>
</div>
...
...
@@ -79,24 +105,37 @@ import { Cookies, $, _, axios, storeToRefs, mainStore, Toast, useTitle } from '@
//import { } from '@/utils/generateModules.js'
//import { } from '@/utils/generateIcons.js'
//import { } from '@/composables'
import { getSkuInfoAPI } from "@/api/material";
const $route = useRoute();
const $router = useRouter();
useTitle($route.meta.title);
const props = defineProps({
show: Boolean,
goodId: Number,
});
const emit = defineEmits(['close']);
const showRight = ref(false);
const onClose = () => {
emit('close');
}
const goodInfo = ref({});
// 监听字段变化
watch(
() => props.show,
(v) => {
async
(v) => {
showRight.value = v;
if (v) {
const { code, data } = await getSkuInfoAPI({ i: props.goodId });
if (code) {
// 物资信息
goodInfo.value = data;
}
}
}
);
</script>
...
...
src/views/material_list.vue
View file @
6203582
<!--
* @Date: 2024-07-23 10:50:38
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-07-2
5 10:00:39
* @LastEditTime: 2024-07-2
6 14:39:00
* @FilePath: /temple_material_request/src/views/material_list.vue
* @Description: 物资情况页面
-->
<template>
<div class="material-list-page">
<van-tabs v-model:active="active" @change="onChange" sticky :color="styleColor.baseColor">
<van-tab v-for="
index in 8" :title="'标签 ' + index"
>
<van-tab v-for="
(item, index) in tabList" :title="item.dept_name" shrink
>
<van-list
v-model:loading="loading"
:finished="finished"
...
...
@@ -18,16 +18,20 @@
<div v-for="item in list" :key="item" class="material-list-item">
<van-row>
<van-col span="14">
<div class="item-title van-ellipsis" :style="{ color: styleColor.baseColor }" @click="onClickTitle(item)">床垫 1.2m*2m</div>
<div class="item-attr">申领人:醒莲 2024/05/23使用 </div>
<div class="item-title van-ellipsis" :style="{ color: styleColor.baseColor }" @click="onClickTitle(item)">{{ item.product_name }} / {{ item.spec }}</div>
<div class="item-attr">
<div v-for="(x, index) in item.order_list" :key="index">
申领人: {{ x.contact_name }} {{ x.use_time }} 使用
</div>
</div>
</van-col>
<van-col span="5">
<div class="item-num-title">申请数量</div>
<div class="item-num van-ellipsis">
200
个</div>
<div class="item-num van-ellipsis">
{{ item.total_apply_number }}
个</div>
</van-col>
<van-col span="5">
<div class="item-num-title">实际领用</div>
<div
class="item-num van-ellipsis">200
个</div>
<div
v-if="item.total_number" class="item-num van-ellipsis">{{ item.total_number }}
个</div>
</van-col>
</van-row>
</div>
...
...
@@ -40,63 +44,105 @@
</div>
</div>
<material-detail :show="show_material_detail" @close="onCloseDetail"></material-detail>
<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 { 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 materialDetail from '@/components/materialDetail/index.vue';
import { getActivityDeptsAPI } from "@/api/material";
import { getActivityDeptsAPI
, getGoodUseListAPI
} from "@/api/material";
const $route = useRoute();
const $router = useRouter();
useTitle($route.meta.title);
// form_id=799652&i=801234&c=35697
const activity_id = $route.query.activity_id ? $route.query.activity_id : '';
const form_id = $route.query.form_id ? $route.query.form_id : '';
const client_id = $route.query.client_id ? $route.query.client_id : '';
onMounted(async () => {
const { data, code } = await getActivityDeptsAPI({ activity_id, is_previous: 0, only_my_dept: 0 });
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
}
})
});
}
}
});
const active = ref(0);
const onChange = (index) => {
console.warn(index);
const onChange = async (index) => {
dept_id.value = tabList.value[index]['dept_id'];
limit.value = 20;
offset.value = 0;
loading.value = false;
finished.value = false;
list.value = [];
}
// TODO: getActivityDeptsAPI,is_previous=0,only_my_dept=0
const tabList = ref([]); // 组别列表
const dept_id = ref('');
const limit = ref(20);
const offset = ref(0);
const list = ref([]);
const loading = ref(false);
const finished = ref(false);
const onLoad = () => {
const onLoad =
async
() => {
// 异步更新数据
// setTimeout 仅做示例,真实场景中一般为 ajax 请求
setTimeout(() => {
for (let i = 0; i < 10; i++) {
list.value.push(list.value.length + 1);
}
// 加载状态结束
const { code, data } = await getGoodUseListAPI({ activity_id, dept_id: dept_id.value, is_previous: 0, offset: offset.value, limit: limit.value });
if (code) {
list.value = _.concat(list.value, data);
list.value = _.uniqBy(list.value, 'good_id');
offset.value = list.value.length;
loading.value = false;
// 数据全部加载完成
if (list.value.length >= 40) {
if (!data.length) {
// 加载状态结束
finished.value = true;
}
}
, 1000);
}
};
const material_id = ref('');
const onClickTitle = (item) => { // 点击物资标题回调
console.warn(item);
show_material_detail.value = true;
material_id.value = item.good_id;
}
const onClickRequest = () => { // 我要申领物资
$router.push({
path: '/material_request'
path: '/material_request',
query: {
activity_id,
form_id,
client_id
}
})
}
...
...
@@ -118,7 +164,7 @@ const onCloseDetail = () => {
margin-bottom: 0.5rem;
}
.item-attr {
font-size: 0.8
5
rem;
font-size: 0.8rem;
color: #8F8F8F;
}
.item-num-title {
...
...
@@ -128,7 +174,7 @@ const onCloseDetail = () => {
margin-bottom: 0.5rem;
}
.item-num {
font-size:
1
rem;
font-size:
0.95
rem;
text-align: center;
}
}
...
...
src/views/material_pre_request.vue
View file @
6203582
<!--
* @Date: 2024-07-23 12:53:15
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-07-2
5 13:21:17
* @LastEditTime: 2024-07-2
6 14:10:50
* @FilePath: /temple_material_request/src/views/material_pre_request.vue
* @Description: 待申领物资页面
-->
...
...
@@ -11,25 +11,23 @@
<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 }"> 全选</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" /> 编辑</span>
<span v-else>
<span @click="onClickDel"><van-icon name="delete-o" /> 删除</span>
<span @click="onClickCancel"><van-icon name="close" />
取消
编辑</span>
<span @click="onClickCancel"><van-icon name="close" />
确认
编辑</span>
</span>
</van-col>
</van-row>
</van-sticky>
<div v-for="item in list" :id="item.id" :key="item" class="list-boxer">
<div v-for="item in list" :id="item.
good_
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">
...
...
@@ -37,12 +35,12 @@
<van-icon v-else name="passed" @click="onCheck(item)" size="1.25rem" />
</span>
<div class="van-ellipsis" :style="{ color: styleColor.baseColor, textDecoration: 'underline' }" @click="onClickTitle(item)">
{{ item.
name
}}
{{ item.
product_name }} / {{ item.spec
}}
</div>
</van-col>
<van-col span="8" style="display: flex; align-items: center;">
<van-field
v-model="item.
num
"
v-model="item.
apply_number
"
style="border: 1px solid #f0f0f0; padding: 0; border-radius: 5px;"
label=""
label-width="0"
...
...
@@ -60,7 +58,7 @@
</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>
<van-button icon="plus" type="primary" :color="styleColor.baseColor" plain block
:disabled="disabled_btn"
@click="addMore">添加更多</van-button>
</div>
</div>
<div class="control-bar">
...
...
@@ -68,10 +66,10 @@
<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>
<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_
dat
e }} <van-icon name="notes-o" size="1rem" :color="styleColor.baseColor" /></div>
<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_
tim
e }} <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>
<van-button type="primary" :color="styleColor.baseColor"
:disabled="disabled_btn"
@click="onConfirmRequest">确定申领</van-button>
</div>
</div>
</div>
...
...
@@ -95,20 +93,18 @@
<!-- <div style="font-size: 0.9rem; margin-right: 1rem; width: 5rem;">申领组: </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 :name="item.dept_id" v-for="(item, index) in my_depts" :key="index" :checked-color="styleColor.baseColor" style="margin-bottom: 0.25rem;">{{ item.dept_name }}</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-col span="17"><van-field v-model="
contact_name
" 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-col span="17"><van-field v-model="
contact_phone" label="" placeholder="请输入" type="tel" maxlength="11
" 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;">
...
...
@@ -122,7 +118,7 @@
</van-dialog>
<choose-material :show="show_choose_material" @close="onCloseChoose"></choose-material>
<material-detail :show="show_material_detail" @close="onCloseDetail"></material-detail>
<material-detail :show="show_material_detail"
:good-id="material_id"
@close="onCloseDetail"></material-detail>
</template>
...
...
@@ -138,25 +134,86 @@ import { styleColor } from "@/constant.js";
import dayjs from "dayjs";
import chooseMaterial from '@/components/chooseMaterial/index.vue';
import materialDetail from '@/components/materialDetail/index.vue';
import { getCartListAPI, delCartAPI, myDeptsAPI, myUserAPI, editCartAPI, addUseOrderAPI } 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 disabled_btn = ref(false);
/**
* 获取我的组别列表
*/
const my_depts = ref([]);
const getDeptsList = async () => {
const { data, code } = await myDeptsAPI();
if (code) {
my_depts.value = data;
if (!data.length) {
showToast('您暂无组别无法申领物资');
disabled_btn.value = true;
}
}
}
/**
* 获取我的用户信息
*/
const getUserList = async () => {
const { data, code } = await myUserAPI();
if (code) {
contact_name.value = data.name;
contact_phone.value = data.mobile;
}
}
/**
* 购物车列表
*/
const getCartList = async () => {
const { data, code } = await getCartListAPI({ activity_id });
if (code) {
list.value = data;
list.value.forEach(item => {
item.checked = false;
})
if (!list.value.length) { // 购物车为空
addMore();
} else {
sum_num.value = list.value.length; // 品项数量
}
}
}
onMounted(async () => {
// 获取列表
getCartList();
getDeptsList();
getUserList();
//
minDate.value = new Date();
});
const is_all_checked = ref(false);
const sum_num = ref(
999); // TODO: 品项的总数量,需要接口提供
const sum_num = ref(
0); // 品项的总数量
const model = ref(''); // 默认非编辑模式
const onClickEdit = () => { // 点击编辑
model.value = 'edit';
disabled_btn.value = true;
list.value.forEach(item => {
item.checked = false;
item.error = false;
item.edit = true;
})
}
const onClickDel = () => { // 点击删除
const onClickDel = () => { // 点击删除
回调
let shop_cart_list = [];
// 把选中的值集合
list.value
...
...
@@ -169,20 +226,25 @@ const onClickDel = () => { // 点击删除
showToast('删除项为空');
return;
}
//
TODO:删除选中的项,接口需要一个购物车删除指定ID的接口
let del_ids = shop_cart_list.map(item => item.id);
console.warn(del_ids);
//
把选中的值集合
let del_ids = shop_cart_list.map(item => item.
good_
id);
// 删除接口
showConfirmDialog({
title: '温馨提示',
message:
`您是否需要删除这 ${del_ids.length} 项物资?`,
confirmButtonColor: styleColor.baseColor,
})
.then(() => {
// on confirm
// 还原列表显示
onClickCancel();
// TODO: 刷新列表
.then(async () => {
const { code, data } = await delCartAPI({ activity_id, good_ids: del_ids });
if (code) {
// 还原列表显示
onClickCancel();
// 获取购物车列表
getCartList();
//
showToast('删除成功');
}
})
.catch(() => {
// on cancel
...
...
@@ -192,11 +254,15 @@ const onClickDel = () => { // 点击删除
const onClickCancel = () => { // 点击取消
if (checkShoppingCart()) {
model.value = '';
disabled_btn.value = false;
is_all_checked.value = false;
list.value.forEach(item => {
item.checked = false;
item.error = false;
item.edit = false;
});
} else {
showToast('请检查输入项')
}
}
...
...
@@ -229,42 +295,25 @@ const onCheck = (item) => {
}
}
const onBlur = (item) => { // 输入框失去焦点回调
if (item.
num === null || item.num
=== '') {
const onBlur =
async
(item) => { // 输入框失去焦点回调
if (item.
apply_number === null || item.apply_number
=== '') {
item.error = true;
} else {
// 输入框失去焦点,购物车更新数量
item.error = false;
const { code, data } = await editCartAPI({ activity_id, good_list: [{ good_id: item.good_id, apply_number: item.apply_number }] });
if (code) {
}
}
// 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 material_id = ref('');
const onClickTitle = (item) => { // 点击物资标题回调
console.warn(item);
show_material_detail.value = true;
material_id.value = item.good_id;
}
const showPicker = ref(false);
...
...
@@ -272,21 +321,14 @@ const currentDate = ref([]);
const columns_type = ref(['year', 'month', 'day']);
const minDate = ref();
const maxDate = ref();
const use_
dat
e = ref('');
const use_
tim
e = ref('');
const onConfirm = ({ selectedValues, selectedOptions }) => {
use_
dat
e.value = selectedValues.join("-");
use_
tim
e.value = selectedValues.join("-");
showPicker.value = false;
};
onMounted(() => {
minDate.value = new Date();
// 测试
onLoad()
})
const addMore = () => { // 添加更多回调
console.warn('addMore');
show_choose_material.value = true;
}
...
...
@@ -295,10 +337,10 @@ 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;} })
let error_list = list.value.filter((item) => { if (item.
apply_number === null || item.apply_number
=== '') { return item;} })
if (error_list.length) {
// 跳到第一个错误框
scrollToSection(error_list[0].id);
scrollToSection(error_list[0].
good_
id);
// 标记所有错误
error_list.forEach(item => {
item.error = true;
...
...
@@ -310,8 +352,7 @@ const checkShoppingCart = () => { // 检查购物车有效性
}
const onConfirmRequest = () => { // 确定申领回调
console.warn('onConfirmRequest');
if (!use_date.value) {
if (!use_time.value) {
showToast('请选择使用日期');
return;
}
...
...
@@ -319,11 +360,11 @@ const onConfirmRequest = () => { // 确定申领回调
}
const scrollToSection = (id) => { // 滚动到指定位置
const current_index = list.value.findIndex((item) => item.id === id);
const current_index = list.value.findIndex((item) => item.
good_
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']}`);
let element = $('.list-wrapper').find(`#${list.value[previous_index]['
good_
id']}`);
if (element[0]) {
element[0].scrollIntoView({ behavior: 'smooth' });
} else {
...
...
@@ -334,26 +375,31 @@ const scrollToSection = (id) => { // 滚动到指定位置
const showType = ref(false);
const type_checked = ref(''); // 组别
const
request_user
= ref(''); // 申领人
const
request_tel
= ref(''); // 联系电话
const onDialogConfirm = () => {
const
contact_name
= ref(''); // 申领人
const
contact_phone
= ref(''); // 联系电话
const onDialogConfirm =
async
() => {
if (!type_checked.value) {
showToast('请选择组别')
}
if (!request_user.value) {
} else if (!contact_name.value) {
showToast('申领人不能为空')
} else if (!contact_phone.value || !contact_phone.value.match(/^1[3456789]\d{9}$/)) {
showToast('联系电话填写有误')
} else {
// 提交申领物资接口
const { code, data } = await addUseOrderAPI({ activity_id, dept_id: type_checked.value, use_time: use_time.value, contact_name: contact_name.value, contact_phone: contact_phone.value });
if (code) {
showType.value = false;
// 申领成功跳转
$router.push({
path: '/success',
query: {
activity_id,
form_id,
client_id
}
});
}
}
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;
...
...
@@ -361,8 +407,9 @@ const onDialogCancel = () => {
const show_choose_material = ref(false);
const onCloseChoose = () => { // 关闭选择物资弹窗回调
// TODO: 需要刷新列表,应该可能新增的物料
show_choose_material.value = false;
// 刷新购物车列表
getCartList();
}
const show_material_detail = ref(false);
...
...
src/views/material_request.vue
View file @
6203582
<!--
* @Date: 2024-07-23 12:53:15
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-07-2
5 10:01:06
* @LastEditTime: 2024-07-2
6 14:42:54
* @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="
index in 8" :title="'标签 ' + index"
>
<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">
...
...
@@ -32,12 +32,12 @@
<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" />
<div class="van-ellipsis" :style="{ color: styleColor.baseColor, textDecoration: 'underline' }" @click="onClickTitle(item)">
{{ item.
name
}}
{{ item.
product_name }} / {{ item.spec
}}
</div>
</van-col>
<van-col span="8" style="display: flex; align-items: center;">
<van-field
v-model="item.
num
"
v-model="item.
total_apply_number
"
style="border: 1px solid #f0f0f0; padding: 0; border-radius: 5px;"
label=""
label-width="0"
...
...
@@ -73,14 +73,14 @@
</div>
<choose-material :show="show_choose_material" @close="onCloseChoose"></choose-material>
<material-detail :show="show_material_detail" @close="onCloseDetail"></material-detail>
<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 } from 'vant';
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'
...
...
@@ -88,14 +88,54 @@ import { Cookies, $, _, axios, storeToRefs, mainStore, Toast, useTitle } from '@
import { styleColor } from "@/constant.js";
import chooseMaterial from '@/components/chooseMaterial/index.vue';
import materialDetail from '@/components/materialDetail/index.vue';
import { getActivityDeptsAPI } from "@/api/material";
import { getActivityDeptsAPI
, getGoodUseListAPI, getCartListAPI, addCartAPI
} from "@/api/material";
const $route = useRoute();
const $router = useRouter();
useTitle($route.meta.title);
// TODO: getActivityDeptsAPI,is_previous=1,only_my_dept=1
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('');
...
...
@@ -130,8 +170,9 @@ const onCheck = (item) => {
}
const onBlur = (item) => { // 输入框失去焦点回调
console.warn(item);
if (item.checked) {
if (item.
num === null || item.num
=== '') {
if (item.
total_apply_number === null || item.total_apply_number
=== '') {
item.error = true;
} else {
item.error = false;
...
...
@@ -144,40 +185,48 @@ const onChange = (index) => { // 切换标签回调
console.warn(index);
// 取消全选
is_all_checked.value = false;
// TODO:重新查询列表数据, 取消选中
list.value.forEach(item => {
item.checked = false;
item.error = 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 onLoad = () => {
// 异步更新数据
// setTimeout 仅做示例,真实场景中一般为 ajax 请求
setTimeout(() => {
for (let i = 0; i < 10; i++) {
list.value.push({ id: list.value.length + 1, name: '标题 床垫 1.2m*2m', num: null, checked: false, error: 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 (list.value.length >= 40) {
if (!data.length) {
// 加载状态结束
finished.value = true;
}
}
, 1000);
}
// TODO: 如果查询到的数据大于0,需要取消全选
is_all_checked.value = false;
};
const material_id = ref('');
const onClickTitle = (item) => { // 点击物资标题回调
console.warn(item);
show_material_detail.value = true;
material_id.value = item.good_id;
}
const addMore = () => { // 添加更多
...
...
@@ -185,9 +234,8 @@ const addMore = () => { // 添加更多
show_choose_material.value = true;
}
const cart_count = ref(0);
const shop_cart_list = ref([]); // 购物车列表
const addShoppingCart = () => { // 加入购物车
const addShoppingCart =
async
() => { // 加入购物车
shop_cart_list.value = [];
// 把选中的值集合
list.value
...
...
@@ -201,7 +249,7 @@ const addShoppingCart = () => { // 加入购物车
return;
}
// 校验购物车值
let error_list = shop_cart_list.value.filter((item) => { if (item.
num === null || item.num
=== '') { return item;} })
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);
...
...
@@ -211,18 +259,66 @@ const addShoppingCart = () => { // 加入购物车
})
return;
}
// 购物车数量
cart_count.value = shop_cart_list.value.length;
//
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 = () => { // 跳转购物车
console.warn('goShoppingCart');
$router.push({ path: '/material_pre_request' });
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
}
});
}
}
const show_choose_material = ref(false);
const onCloseChoose = () => { // 关闭选择物资弹窗回调
show_choose_material.value = false;
// 购物车数量
getCartCount();
}
const show_material_detail = ref(false);
...
...
src/views/success.vue
View file @
6203582
<!--
* @Date: 2022-06-29 18:18:02
* @LastEditors: hookehuyr hookehuyr@gmail.com
* @LastEditTime: 2024-07-2
4 18:25:08
* @LastEditTime: 2024-07-2
5 17:30:16
* @FilePath: /temple_material_request/src/views/success.vue
* @Description: 文件描述
-->
...
...
@@ -65,8 +65,15 @@ const goTo = (type) => {
// TODO:地址待定需要和后台沟通
if (type === 'home') { // 返回首页
// location.href = '/';
/**
* 活动首页:
http://oa.onwall.cn/f/main/?p=activity&form_id=799652&i=801234
*/
} else { // 返回活动主页
// location.href = '/';
/**
* https://oa-dev.onwall.cn/?p=volunteer_home&t=volunteer&c=35697
*/
}
console.warn(type);
}
...
...
Please
register
or
login
to post a comment