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:21:02 4 + * @LastEditTime: 2024-07-24 16:52:35
5 * @FilePath: /temple_material_request/src/views/material_pre_request.vue 5 * @FilePath: /temple_material_request/src/views/material_pre_request.vue
6 * @Description: 待申领物资页面 6 * @Description: 待申领物资页面
7 --> 7 -->
...@@ -12,13 +12,20 @@ ...@@ -12,13 +12,20 @@
12 <van-row justify="space-between" class="select-all-item"> 12 <van-row justify="space-between" class="select-all-item">
13 <van-col span="8"> 13 <van-col span="8">
14 <!-- TODO:编辑模式下,不能确认申请 --> 14 <!-- TODO:编辑模式下,不能确认申请 -->
15 - <van-icon name="passed" size="1.25rem" />&nbsp;&nbsp;<span :style="{ color: styleColor.baseColor }">全选</span> 15 + <span v-if="model === 'edit'">
16 + <van-icon v-if="is_all_checked" @click="onCheckAll()" name="checked" size="1.25rem" :color="styleColor.baseColor" />
17 + <van-icon v-else name="passed" @click="onCheckAll()" size="1.25rem" />
18 + <span @click="onCheckAll()" :style="{ color: styleColor.baseColor }">&nbsp;&nbsp;全选</span>
19 + </span>
16 <!-- TODO:非编辑模式下,显示购物车总数量 --> 20 <!-- TODO:非编辑模式下,显示购物车总数量 -->
17 - <span :style="{ color: styleColor.baseColor }">品项数: 1000</span> 21 + <span v-else :style="{ color: styleColor.baseColor }">品项数: {{ sum_num }}</span>
18 </van-col> 22 </van-col>
19 <van-col span="16" :style="{ textAlign: 'right', fontSize: '0.85rem', color: styleColor.baseColor }"> 23 <van-col span="16" :style="{ textAlign: 'right', fontSize: '0.85rem', color: styleColor.baseColor }">
20 - <van-icon name="records-o" />&nbsp;编辑 24 + <span v-if="model !== 'edit'" @click="onClickEdit"><van-icon name="records-o" />&nbsp;编辑</span>
21 - <van-icon name="delete-o" />&nbsp;删除 25 + <span v-else>
26 + <span @click="onClickDel"><van-icon name="delete-o" />&nbsp;删除</span>&nbsp;&nbsp;
27 + <span @click="onClickCancel"><van-icon name="close" />&nbsp;取消编辑</span>
28 + </span>
22 </van-col> 29 </van-col>
23 </van-row> 30 </van-row>
24 </van-sticky> 31 </van-sticky>
...@@ -28,17 +35,34 @@ ...@@ -28,17 +35,34 @@
28 finished-text="没有更多了" 35 finished-text="没有更多了"
29 @load="onLoad" 36 @load="onLoad"
30 > 37 >
31 - <div v-for="item in list" :key="item" class="list-boxer"> 38 + <div v-for="item in list" :id="item.id" :key="item" class="list-boxer">
32 <van-row align="center" justify="space-between"> 39 <van-row align="center" justify="space-between">
33 <van-col span="16" style="display: flex;"> 40 <van-col span="16" style="display: flex;">
34 - <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> 41 + <span v-if="item.edit">
42 + <van-icon v-if="item.checked" @click="onCheck(item)" name="checked" size="1.25rem" :color="styleColor.baseColor" />
43 + <van-icon v-else name="passed" @click="onCheck(item)" size="1.25rem" />&nbsp;&nbsp;
44 + </span>
45 + <div class="van-ellipsis" :style="{ color: styleColor.baseColor, textDecoration: 'underline' }" @click="onClickTitle(item)">
46 + {{ item.name }}
47 + </div>
35 </van-col> 48 </van-col>
36 <van-col span="8" style="display: flex; align-items: center;"> 49 <van-col span="8" style="display: flex; align-items: center;">
37 - <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" > 50 + <van-field
51 + v-model="item.num"
52 + style="border: 1px solid #f0f0f0; padding: 0; border-radius: 5px;"
53 + label=""
54 + label-width="0"
55 + input-align="center"
56 + placeholder="数量"
57 + type="number"
58 + :disabled="!item.edit"
59 + @blur="onBlur(item)"
60 + >
38 <template #left-icon></template> 61 <template #left-icon></template>
39 </van-field>&nbsp;&nbsp;<span style="font-size: 0.9rem; color: #666;">个</span> 62 </van-field>&nbsp;&nbsp;<span style="font-size: 0.9rem; color: #666;">个</span>
40 </van-col> 63 </van-col>
41 </van-row> 64 </van-row>
65 + <div v-if="item.error" style="padding: 0.5rem 2rem 0 0; font-size: 0.85rem; color: red; text-align: right;">输入值有误</div>
42 </div> 66 </div>
43 </van-list> 67 </van-list>
44 <div style="height: 6rem;"></div> 68 <div style="height: 6rem;"></div>
...@@ -72,7 +96,7 @@ ...@@ -72,7 +96,7 @@
72 /> 96 />
73 </van-popup> 97 </van-popup>
74 98
75 - <van-dialog v-model:show="showType" @confirm="onDialogConfirm" title="" show-cancel-button :confirm-button-color="styleColor.baseColor"> 99 + <van-dialog v-model:show="showType" title="" :show-cancel-button="false" :show-confirm-button="false">
76 <div style="padding: 1.5rem 0 0; text-align: center; font-size: 0.95rem; font-weight: bold;">请确认您本次是为哪个组别申领物资</div> 100 <div style="padding: 1.5rem 0 0; text-align: center; font-size: 0.95rem; font-weight: bold;">请确认您本次是为哪个组别申领物资</div>
77 <div style="display: flex; align-items: center; padding: 1rem;"> 101 <div style="display: flex; align-items: center; padding: 1rem;">
78 <!-- <div style="font-size: 0.9rem; margin-right: 1rem; width: 5rem;">申领组:&nbsp;&nbsp;</div> --> 102 <!-- <div style="font-size: 0.9rem; margin-right: 1rem; width: 5rem;">申领组:&nbsp;&nbsp;</div> -->
...@@ -86,14 +110,22 @@ ...@@ -86,14 +110,22 @@
86 </div> 110 </div>
87 <div style="padding: 0 1rem;"> 111 <div style="padding: 0 1rem;">
88 <van-row gutter="10" align="center" style="margin-bottom: 0.5rem;"> 112 <van-row gutter="10" align="center" style="margin-bottom: 0.5rem;">
89 - <van-col span="7" style="text-align: right;">申领人:</van-col> 113 + <van-col span="7" style="text-align: right;"><span style="color: red;">*</span>申领人:</van-col>
90 - <van-col span="17"><van-field v-model="value" label="" placeholder="请输入" style="border: 1px solid #DBDBDB; padding: 0.25rem 1rem; border-radius: 5px;" /></van-col> 114 + <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>
91 </van-row> 115 </van-row>
92 <van-row gutter="10" align="center" style="margin-bottom: 1rem;"> 116 <van-row gutter="10" align="center" style="margin-bottom: 1rem;">
93 - <van-col span="7" style="text-align: right;">联系电话:</van-col> 117 + <van-col span="7" style="text-align: right;"><span style="color: red;">*</span>联系电话:</van-col>
94 - <van-col span="17"><van-field v-model="value" label="" placeholder="请输入" type="number" style="border: 1px solid #DBDBDB; padding: 0.25rem 1rem; border-radius: 5px;" /></van-col> 118 + <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>
95 </van-row> 119 </van-row>
96 </div> 120 </div>
121 + <van-row gutter="20" justify="space-around" align="center" style="padding: 1rem; border-top: 1px solid #E9E9E9; text-align: center;">
122 + <van-col span="12">
123 + <van-button plain block color="#A67939" @click="onDialogCancel">取消</van-button>
124 + </van-col>
125 + <van-col span="12">
126 + <van-button block color="#A67939" @click="onDialogConfirm">确定</van-button>
127 + </van-col>
128 + </van-row>
97 </van-dialog> 129 </van-dialog>
98 130
99 <choose-material :show="show_choose_material" @close="onCloseChoose"></choose-material> 131 <choose-material :show="show_choose_material" @close="onCloseChoose"></choose-material>
...@@ -104,7 +136,7 @@ ...@@ -104,7 +136,7 @@
104 <script setup> 136 <script setup>
105 import { ref } from 'vue' 137 import { ref } from 'vue'
106 import { useRoute, useRouter } from 'vue-router' 138 import { useRoute, useRouter } from 'vue-router'
107 - 139 +import { showToast, showConfirmDialog } from 'vant';
108 import { Cookies, $, _, axios, storeToRefs, mainStore, Toast, useTitle } from '@/utils/generatePackage.js' 140 import { Cookies, $, _, axios, storeToRefs, mainStore, Toast, useTitle } from '@/utils/generatePackage.js'
109 //import { } from '@/utils/generateModules.js' 141 //import { } from '@/utils/generateModules.js'
110 //import { } from '@/utils/generateIcons.js' 142 //import { } from '@/utils/generateIcons.js'
...@@ -118,7 +150,100 @@ const $route = useRoute(); ...@@ -118,7 +150,100 @@ const $route = useRoute();
118 const $router = useRouter(); 150 const $router = useRouter();
119 useTitle($route.meta.title); 151 useTitle($route.meta.title);
120 152
121 -const num_value = ref(''); 153 +const is_all_checked = ref(false);
154 +
155 +const sum_num = ref(999); // TODO: 品项的总数量,需要接口提供
156 +const model = ref(''); // 默认非编辑模式
157 +
158 +const onClickEdit = () => { // 点击编辑
159 + model.value = 'edit';
160 + list.value.forEach(item => {
161 + item.checked = false;
162 + item.error = false;
163 + item.edit = true;
164 + })
165 +}
166 +const onClickDel = () => { // 点击删除
167 + let shop_cart_list = [];
168 + // 把选中的值集合
169 + list.value
170 + .filter(item => item.checked)
171 + .forEach(item => {
172 + shop_cart_list = shop_cart_list.concat(item);
173 + });
174 + // 购物车为空提示
175 + if (!shop_cart_list.length) {
176 + showToast('删除项为空');
177 + return;
178 + }
179 + // TODO:删除选中的项,接口需要一个购物车删除指定ID的接口
180 + let del_ids = shop_cart_list.map(item => item.id);
181 + console.warn(del_ids);
182 + showConfirmDialog({
183 + title: '温馨提示',
184 + message:
185 + `您是否需要删除这 ${del_ids.length} 项物资?`,
186 + confirmButtonColor: styleColor.baseColor,
187 + })
188 + .then(() => {
189 + // on confirm
190 + // 还原列表显示
191 + onClickCancel();
192 + // TODO: 刷新列表
193 + })
194 + .catch(() => {
195 + // on cancel
196 + });
197 +}
198 +
199 +const onClickCancel = () => { // 点击取消
200 + if (checkShoppingCart()) {
201 + model.value = '';
202 + is_all_checked.value = false;
203 + list.value.forEach(item => {
204 + item.error = false;
205 + item.edit = false;
206 + });
207 + }
208 +}
209 +
210 +const onCheckAll = () => {
211 + is_all_checked.value = !is_all_checked.value;
212 + if (is_all_checked.value) {
213 + list.value.forEach(item => {
214 + item.checked = true;
215 + })
216 + } else {
217 + list.value.forEach(item => {
218 + item.checked = false;
219 + item.error = false;
220 + })
221 + }
222 +}
223 +
224 +const onCheck = (item) => {
225 + item.checked = !item.checked;
226 + // 全部为选中
227 + let all_checked = list.value.every((item) => item.checked === true);
228 + if (all_checked) {
229 + is_all_checked.value = true;
230 + } else {
231 + is_all_checked.value = false;
232 + }
233 + // 如果取消选中,隐藏错误提示
234 + if (!item.checked) {
235 + item.error = false;
236 + }
237 +}
238 +
239 +const onBlur = (item) => { // 输入框失去焦点回调
240 + if (item.num === null || item.num === '') {
241 + item.error = true;
242 + } else {
243 + item.error = false;
244 + }
245 + // TODO: 输入框失去焦点,接口需要一个购物车更新接口
246 +}
122 247
123 const list = ref([]); 248 const list = ref([]);
124 const loading = ref(false); 249 const loading = ref(false);
...@@ -129,7 +254,7 @@ const onLoad = () => { ...@@ -129,7 +254,7 @@ const onLoad = () => {
129 // setTimeout 仅做示例,真实场景中一般为 ajax 请求 254 // setTimeout 仅做示例,真实场景中一般为 ajax 请求
130 setTimeout(() => { 255 setTimeout(() => {
131 for (let i = 0; i < 10; i++) { 256 for (let i = 0; i < 10; i++) {
132 - list.value.push(list.value.length + 1); 257 + list.value.push({ id: list.value.length + 1, name: '标题 床垫 1.2m*2m', num: 11, checked: false, error: false, edit: model.value === 'edit' });
133 } 258 }
134 259
135 // 加载状态结束 260 // 加载状态结束
...@@ -140,6 +265,8 @@ const onLoad = () => { ...@@ -140,6 +265,8 @@ const onLoad = () => {
140 finished.value = true; 265 finished.value = true;
141 } 266 }
142 }, 1000); 267 }, 1000);
268 + // TODO: 如果查询到的数据大于0,需要取消全选
269 + is_all_checked.value = false;
143 }; 270 };
144 271
145 const onClickTitle = (item) => { // 点击物资标题回调 272 const onClickTitle = (item) => { // 点击物资标题回调
...@@ -168,25 +295,81 @@ const addMore = () => { // 添加更多回调 ...@@ -168,25 +295,81 @@ const addMore = () => { // 添加更多回调
168 show_choose_material.value = true; 295 show_choose_material.value = true;
169 } 296 }
170 297
298 +const shop_cart_list = ref([]); // 购物车列表
299 +
300 +const checkShoppingCart = () => { // 检查购物车有效性
301 + let flag = true;
302 + // 校验购物车值
303 + let error_list = list.value.filter((item) => { if (item.num === null || item.num === '') { return item;} })
304 + if (error_list.length) {
305 + // 跳到第一个错误框
306 + scrollToSection(error_list[0].id);
307 + // 标记所有错误
308 + error_list.forEach(item => {
309 + item.error = true;
310 + });
311 + flag = false
312 + return;
313 + }
314 + return flag;
315 +}
316 +
171 const onConfirmRequest = () => { // 确定申领回调 317 const onConfirmRequest = () => { // 确定申领回调
172 console.warn('onConfirmRequest'); 318 console.warn('onConfirmRequest');
319 + if (!use_date.value) {
320 + showToast('请选择使用日期');
321 + return;
322 + }
173 showType.value = true; 323 showType.value = true;
174 } 324 }
175 325
176 -const showType = ref(false); 326 +const scrollToSection = (id) => { // 滚动到指定位置
177 -const type_checked = ref(''); 327 + const current_index = list.value.findIndex((item) => item.id === id);
328 + // 因为布局问题,需要滚动到上一个节点 查询上一个节点ID
329 + const previous_index = current_index - 2 >= 0 ? current_index - 2 : 0;
330 + nextTick(() => {
331 + let element = $('.list-wrapper').find(`#${list.value[previous_index]['id']}`);
332 + if (element[0]) {
333 + element[0].scrollIntoView({ behavior: 'smooth' });
334 + } else {
335 + console.log('Element with ID ' + id + ' not found.');
336 + }
337 + })
338 +}
178 339
340 +const showType = ref(false);
341 +const type_checked = ref(''); // 组别
342 +const request_user = ref(''); // 申领人
343 +const request_tel = ref(''); // 联系电话
179 const onDialogConfirm = () => { 344 const onDialogConfirm = () => {
180 - console.warn(type_checked.value); 345 + if (!type_checked.value) {
346 + showToast('请选择组别')
347 + }
348 + if (!request_user.value) {
349 + showToast('申领人不能为空')
350 + }
351 + if (!request_tel.value) {
352 + showToast('联系电话不能为空')
353 + }
354 + console.warn('组别', type_checked.value);
355 + console.warn('use_date', use_date.value);
356 + console.warn('request_user', request_user.value);
357 + console.warn('request_tel', request_tel.value);
358 + // TODO:购物车的值应该不用传,数量应该是单独修改
359 + showType.value = false;
360 +}
361 +const onDialogCancel = () => {
362 + showType.value = false;
181 } 363 }
182 364
183 const show_choose_material = ref(false); 365 const show_choose_material = ref(false);
184 -const onCloseChoose = () => { 366 +const onCloseChoose = () => { // 关闭选择物资弹窗回调
367 + // TODO: 需要刷新列表,应该可能新增的物料
185 show_choose_material.value = false; 368 show_choose_material.value = false;
186 } 369 }
187 370
188 const show_material_detail = ref(false); 371 const show_material_detail = ref(false);
189 -const onCloseDetail = () => { 372 +const onCloseDetail = () => { // 关闭物资详情窗口
190 show_material_detail.value = false; 373 show_material_detail.value = false;
191 } 374 }
192 </script> 375 </script>
......
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 14:44:31 4 + * @LastEditTime: 2024-07-24 15:15:38
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 -
11 <van-tabs v-model:active="active" @change="onChange" sticky :color="styleColor.baseColor"> 10 <van-tabs v-model:active="active" @change="onChange" sticky :color="styleColor.baseColor">
12 <van-tab v-for="index in 8" :title="'标签 ' + index"> 11 <van-tab v-for="index in 8" :title="'标签 ' + index">
13 <div class="list-wrapper"> 12 <div class="list-wrapper">
...@@ -81,7 +80,7 @@ ...@@ -81,7 +80,7 @@
81 <script setup> 80 <script setup>
82 import { ref } from 'vue' 81 import { ref } from 'vue'
83 import { useRoute, useRouter } from 'vue-router' 82 import { useRoute, useRouter } from 'vue-router'
84 - 83 +import { showToast } from 'vant';
85 import { Cookies, $, _, axios, storeToRefs, mainStore, Toast, useTitle } from '@/utils/generatePackage.js' 84 import { Cookies, $, _, axios, storeToRefs, mainStore, Toast, useTitle } from '@/utils/generatePackage.js'
86 //import { } from '@/utils/generateModules.js' 85 //import { } from '@/utils/generateModules.js'
87 //import { } from '@/utils/generateIcons.js' 86 //import { } from '@/utils/generateIcons.js'
...@@ -192,6 +191,11 @@ const addShoppingCart = () => { // 加入购物车 ...@@ -192,6 +191,11 @@ const addShoppingCart = () => { // 加入购物车
192 .forEach(item => { 191 .forEach(item => {
193 shop_cart_list.value = shop_cart_list.value.concat(item); 192 shop_cart_list.value = shop_cart_list.value.concat(item);
194 }); 193 });
194 + // 购物车为空提示
195 + if (!shop_cart_list.value.length) {
196 + showToast('请选择物资');
197 + return;
198 + }
195 // 校验购物车值 199 // 校验购物车值
196 let error_list = shop_cart_list.value.filter((item) => { if (item.num === null || item.num === '') { return item;} }) 200 let error_list = shop_cart_list.value.filter((item) => { if (item.num === null || item.num === '') { return item;} })
197 if (error_list.length) { 201 if (error_list.length) {
...@@ -213,7 +217,7 @@ const goShoppingCart = () => { // 跳转购物车 ...@@ -213,7 +217,7 @@ const goShoppingCart = () => { // 跳转购物车
213 } 217 }
214 218
215 const show_choose_material = ref(false); 219 const show_choose_material = ref(false);
216 -const onCloseChoose = () => { 220 +const onCloseChoose = () => { // 关闭选择物资弹窗回调
217 show_choose_material.value = false; 221 show_choose_material.value = false;
218 } 222 }
219 223
......