hookehuyr

完善申领物资页面,选择逻辑,加入购物车逻辑,填写数量逻辑

1 <!-- 1 <!--
2 * @Date: 2024-07-23 12:53:15 2 * @Date: 2024-07-23 12:53:15
3 * @LastEditors: hookehuyr hookehuyr@gmail.com 3 * @LastEditors: hookehuyr hookehuyr@gmail.com
4 - * @LastEditTime: 2024-07-24 11:05:03 4 + * @LastEditTime: 2024-07-24 14:44:31
5 * @FilePath: /temple_material_request/src/views/material_request.vue 5 * @FilePath: /temple_material_request/src/views/material_request.vue
6 * @Description: 申领物资页面 6 * @Description: 申领物资页面
7 --> 7 -->
8 <template> 8 <template>
9 <div class="material-request-page"> 9 <div class="material-request-page">
10 +
10 <van-tabs v-model:active="active" @change="onChange" sticky :color="styleColor.baseColor"> 11 <van-tabs v-model:active="active" @change="onChange" sticky :color="styleColor.baseColor">
11 <van-tab v-for="index in 8" :title="'标签 ' + index"> 12 <van-tab v-for="index in 8" :title="'标签 ' + index">
12 <div class="list-wrapper"> 13 <div class="list-wrapper">
13 <van-sticky :offset-top="44"> 14 <van-sticky :offset-top="44">
14 <van-row justify="space-between" class="select-all-item"> 15 <van-row justify="space-between" class="select-all-item">
15 - <van-col span="8"><van-icon name="passed" size="1.25rem" />&nbsp;&nbsp;<span :style="{ color: styleColor.baseColor }">全选</span></van-col> 16 + <van-col span="8">
17 + <van-icon v-if="is_all_checked" @click="onCheckAll()" name="checked" size="1.25rem" :color="styleColor.baseColor" />
18 + <van-icon v-else name="passed" @click="onCheckAll()" size="1.25rem" />
19 + <span @click="onCheckAll()" :style="{ color: styleColor.baseColor }">&nbsp;&nbsp;全选</span>
20 + </van-col>
16 <van-col span="16" style="text-align: right; font-size: 0.85rem; color: #666666;">参考上次同类活动的领用情况</van-col> 21 <van-col span="16" style="text-align: right; font-size: 0.85rem; color: #666666;">参考上次同类活动的领用情况</van-col>
17 </van-row> 22 </van-row>
18 </van-sticky> 23 </van-sticky>
...@@ -22,17 +27,31 @@ ...@@ -22,17 +27,31 @@
22 finished-text="没有更多了" 27 finished-text="没有更多了"
23 @load="onLoad" 28 @load="onLoad"
24 > 29 >
25 - <div v-for="item in list" :key="item" class="list-boxer"> 30 + <div v-for="item in list" :id="item.id" :key="item.id" class="list-boxer">
26 <van-row align="center" justify="space-between"> 31 <van-row align="center" justify="space-between">
27 <van-col span="16" style="display: flex;"> 32 <van-col span="16" style="display: flex;">
28 - <van-icon name="passed" size="1.25rem" />&nbsp;&nbsp;<div class="van-ellipsis" :style="{ color: styleColor.baseColor, textDecoration: 'underline' }" @click="onClickTitle(item)">床垫 1.2m*2m</div> 33 + <van-icon v-if="item.checked" @click="onCheck(item)" name="checked" size="1.25rem" :color="styleColor.baseColor" />
34 + <van-icon v-else name="passed" @click="onCheck(item)" size="1.25rem" />&nbsp;&nbsp;
35 + <div class="van-ellipsis" :style="{ color: styleColor.baseColor, textDecoration: 'underline' }" @click="onClickTitle(item)">
36 + {{ item.name }}
37 + </div>
29 </van-col> 38 </van-col>
30 <van-col span="8" style="display: flex; align-items: center;"> 39 <van-col span="8" style="display: flex; align-items: center;">
31 - <van-field v-model="num_value" style="border: 1px solid #f0f0f0; padding: 0; border-radius: 5px;" label="" label-width="0" input-align="center" placeholder="数量" type="number" > 40 + <van-field
41 + v-model="item.num"
42 + style="border: 1px solid #f0f0f0; padding: 0; border-radius: 5px;"
43 + label=""
44 + label-width="0"
45 + input-align="center"
46 + placeholder="数量"
47 + type="number"
48 + @blur="onBlur(item)"
49 + >
32 <template #left-icon></template> 50 <template #left-icon></template>
33 </van-field>&nbsp;&nbsp;<span style="font-size: 0.9rem; color: #666;">个</span> 51 </van-field>&nbsp;&nbsp;<span style="font-size: 0.9rem; color: #666;">个</span>
34 </van-col> 52 </van-col>
35 </van-row> 53 </van-row>
54 + <div v-if="item.error" style="padding: 0.5rem 2rem 0 0; font-size: 0.85rem; color: red; text-align: right;">输入值有误</div>
36 </div> 55 </div>
37 </van-list> 56 </van-list>
38 <div style="height: 6rem;"></div> 57 <div style="height: 6rem;"></div>
...@@ -46,11 +65,12 @@ ...@@ -46,11 +65,12 @@
46 <div style="display: flex; align-items: center;"> 65 <div style="display: flex; align-items: center;">
47 <van-button plain type="primary" :color="styleColor.baseColor" @click="addShoppingCart">加入购物车</van-button> 66 <van-button plain type="primary" :color="styleColor.baseColor" @click="addShoppingCart">加入购物车</van-button>
48 &nbsp;&nbsp; 67 &nbsp;&nbsp;
49 - <van-badge :content="5"> 68 + <van-badge :content="cart_count">
50 <van-icon name="shopping-cart-o" size="2.5rem" :color="styleColor.baseColor" @click="goShoppingCart" /> 69 <van-icon name="shopping-cart-o" size="2.5rem" :color="styleColor.baseColor" @click="goShoppingCart" />
51 </van-badge> 70 </van-badge>
52 </div> 71 </div>
53 </div> 72 </div>
73 +
54 </div> 74 </div>
55 75
56 <choose-material :show="show_choose_material" @close="onCloseChoose"></choose-material> 76 <choose-material :show="show_choose_material" @close="onCloseChoose"></choose-material>
...@@ -74,11 +94,58 @@ const $route = useRoute(); ...@@ -74,11 +94,58 @@ const $route = useRoute();
74 const $router = useRouter(); 94 const $router = useRouter();
75 useTitle($route.meta.title); 95 useTitle($route.meta.title);
76 96
97 +const is_all_checked = ref(false);
77 const num_value = ref(''); 98 const num_value = ref('');
78 99
100 +const onCheckAll = () => {
101 + is_all_checked.value = !is_all_checked.value;
102 + if (is_all_checked.value) {
103 + list.value.forEach(item => {
104 + item.checked = true;
105 + })
106 + } else {
107 + list.value.forEach(item => {
108 + item.checked = false;
109 + item.error = false;
110 + })
111 + }
112 +}
113 +
114 +const onCheck = (item) => {
115 + item.checked = !item.checked;
116 + // 全部为选中
117 + let all_checked = list.value.every((item) => item.checked === true);
118 + if (all_checked) {
119 + is_all_checked.value = true;
120 + } else {
121 + is_all_checked.value = false;
122 + }
123 + // 如果取消选中,隐藏错误提示
124 + if (!item.checked) {
125 + item.error = false;
126 + }
127 +}
128 +
129 +const onBlur = (item) => { // 输入框失去焦点回调
130 + if (item.checked) {
131 + if (item.num === null || item.num === '') {
132 + item.error = true;
133 + } else {
134 + item.error = false;
135 + }
136 + }
137 +}
138 +
79 const active = ref(0); 139 const active = ref(0);
80 -const onChange = (index) => { 140 +const onChange = (index) => { // 切换标签回调
81 console.warn(index); 141 console.warn(index);
142 + // 取消全选
143 + is_all_checked.value = false;
144 + // TODO:重新查询列表数据, 取消选中
145 + list.value.forEach(item => {
146 + item.checked = false;
147 + item.error = false;
148 + });
82 } 149 }
83 150
84 const list = ref([]); 151 const list = ref([]);
...@@ -90,7 +157,7 @@ const onLoad = () => { ...@@ -90,7 +157,7 @@ const onLoad = () => {
90 // setTimeout 仅做示例,真实场景中一般为 ajax 请求 157 // setTimeout 仅做示例,真实场景中一般为 ajax 请求
91 setTimeout(() => { 158 setTimeout(() => {
92 for (let i = 0; i < 10; i++) { 159 for (let i = 0; i < 10; i++) {
93 - list.value.push(list.value.length + 1); 160 + list.value.push({ id: list.value.length + 1, name: '标题 床垫 1.2m*2m', num: null, checked: false, error: false });
94 } 161 }
95 162
96 // 加载状态结束 163 // 加载状态结束
...@@ -101,6 +168,8 @@ const onLoad = () => { ...@@ -101,6 +168,8 @@ const onLoad = () => {
101 finished.value = true; 168 finished.value = true;
102 } 169 }
103 }, 1000); 170 }, 1000);
171 + // TODO: 如果查询到的数据大于0,需要取消全选
172 + is_all_checked.value = false;
104 }; 173 };
105 174
106 const onClickTitle = (item) => { // 点击物资标题回调 175 const onClickTitle = (item) => { // 点击物资标题回调
...@@ -113,8 +182,29 @@ const addMore = () => { // 添加更多 ...@@ -113,8 +182,29 @@ const addMore = () => { // 添加更多
113 show_choose_material.value = true; 182 show_choose_material.value = true;
114 } 183 }
115 184
185 +const cart_count = ref(0);
186 +const shop_cart_list = ref([]); // 购物车列表
116 const addShoppingCart = () => { // 加入购物车 187 const addShoppingCart = () => { // 加入购物车
117 - console.warn('addShoppingCart'); 188 + shop_cart_list.value = [];
189 + // 把选中的值集合
190 + list.value
191 + .filter(item => item.checked)
192 + .forEach(item => {
193 + shop_cart_list.value = shop_cart_list.value.concat(item);
194 + });
195 + // 校验购物车值
196 + let error_list = shop_cart_list.value.filter((item) => { if (item.num === null || item.num === '') { return item;} })
197 + if (error_list.length) {
198 + // 跳到第一个错误框
199 + scrollToSection(error_list[0].id);
200 + // 标记所有错误
201 + error_list.forEach(item => {
202 + item.error = true;
203 + })
204 + return;
205 + }
206 + // 购物车数量
207 + cart_count.value = shop_cart_list.value.length;
118 } 208 }
119 209
120 const goShoppingCart = () => { // 跳转购物车 210 const goShoppingCart = () => { // 跳转购物车
...@@ -131,6 +221,20 @@ const show_material_detail = ref(false); ...@@ -131,6 +221,20 @@ const show_material_detail = ref(false);
131 const onCloseDetail = () => { 221 const onCloseDetail = () => {
132 show_material_detail.value = false; 222 show_material_detail.value = false;
133 } 223 }
224 +
225 +const scrollToSection = (id) => { // 滚动到指定位置
226 + const current_index = list.value.findIndex((item) => item.id === id);
227 + // 因为布局问题,需要滚动到上一个节点 查询上一个节点ID
228 + const previous_index = current_index - 2 >= 0 ? current_index - 2 : 0;
229 + nextTick(() => {
230 + let element = $('.list-wrapper').find(`#${list.value[previous_index]['id']}`);
231 + if (element[0]) {
232 + element[0].scrollIntoView({ behavior: 'smooth' });
233 + } else {
234 + console.log('Element with ID ' + id + ' not found.');
235 + }
236 + })
237 +}
134 </script> 238 </script>
135 239
136 <style lang="less" scoped> 240 <style lang="less" scoped>
......