Overview
Preventing Page Scaling
To disable user zoom functionality:
<meta name="viewport" content="width=device-width,initial-scale=1.0,user-scalable=no">
State Management for Categories
mapActions Helper Funciton
methods: {
...mapActions({
fetchCategoryList: 'fetchCategoryList'
}),
}
// Invoke using this.fetchCategoryList()
Namespacing
When multiple modules have identical action names, implement namespaced: true during store definition to avoid conflicts. Call actions using module prefixes like /category/fetchProductList.
Order Submission Process
The system retrieves product IDs, user IDs, and item quantities to create orders. It also handles cart ID removal upon order creation.
Implementation involves clearing selection data before capturing selected items:
<template>
<button @click="processOrder">Process Order</button>
</template>
<script>
data() {
return {
cartItems: [],
selectedItems: [],
hasSelection: false,
selectAll: true
}
},
methods: {
processOrder() {
this.selectedItems = [];
this.cartItems.forEach(item => {
if (item.checked) {
this.selectedItems.push(item);
}
});
console.log(this.selectedItems);
}
}
</script>
Order-related API Endpoints
Backend Route Configuration
Configure routes in day06/myapp/routes/order.js and register in app.js.
Database Collecsion Design
Create sql/collection/orders.js:
const mongoose = require('../db.js');
const Schema = mongoose.Schema;
const orderSchema = new Schema({
orderId: {type: String},
userId: {type: String},
status: {type: Number}, // 0=pending payment, 1=shipped, 2=pending review, 3=all orders
items: {type: Array}
});
module.exports = mongoose.model('Order', orderSchema);
Order Creation Endpoint
router.get('/create', (req, res, next) => {
const orderData = JSON.parse(req.query.data);
const userId = req.query.userId;
const orderId = 'order_' + uuid.v1();
const orderItems = [];
orderData.forEach(item => {
orderItems.push({
productId: item.productId,
image: item.image,
name: item.name,
price: parseFloat(item.price),
quantity: parseInt(item.quantity)
});
});
sql.insert(Order, {
orderId: orderId,
userId: userId,
status: 0,
items: orderItems
}).then(() => {
res.json({
code: '200',
message: 'Order created successfully'
});
});
});
Cart Cleanup After Order Creation
Use Promise.all to handle asynchronous loop operations:
router.get('/create', (req, res, next) => {
const orderData = JSON.parse(req.query.data);
const userId = req.query.userId;
const orderId = 'order_' + uuid.v1();
const orderItems = [];
orderData.forEach(item => {
orderItems.push({
productId: item.productId,
image: item.image,
name: item.name,
price: parseFloat(item.price),
quantity: parseInt(item.quantity)
});
});
sql.insert(Order, {
orderId: orderId,
userId: userId,
status: 0,
items: orderItems
}).then(() => {
const deletionPromises = orderData.map(item => {
return sql.delete(Cart, { cartId: item.cartId });
});
return Promise.all(deletionPromises);
}).then(() => {
res.json({
code: '200',
message: 'Order created',
data: {
orderId: orderId
}
});
});
});
Order Retrieval
router.get('/', (req, res, next) => {
const status = req.query.status;
let query = { userId: req.query.userId, orderId: req.query.orderId };
if (status) {
query.status = status;
}
sql.find(Order, query, { _id: 0 }).then(data => {
res.json({
code: '200',
message: 'Order list retrieved',
length: data.length,
data: data
});
});
});
Order Interface Implementation
Cart Page Order Submission
In views/cart/index.vue:
processOrder() {
this.selectedItems = [];
this.cartItems.forEach(item => {
if (item.checked) {
this.selectedItems.push(item);
}
});
if (this.selectedItems.length === 0) {
Toast('Please select items first');
return;
}
axios.get('/order/create?data=' + JSON.stringify(this.selectedItems) + '&userId=' + localStorage.getItem('userId')).then(response => {
console.log('order response', response.data);
this.$router.push('/order?orderId=' + response.data.data.orderId);
});
}
Order Display Page
In views/order/index.vue:
Basic structure and JavaScript implementation:
import axios from '@/utils/request';
export default {
data() {
return {
orderItems: []
}
},
created() {
console.log(this.$route.query);
const userId = localStorage.getItem('userId');
axios.get('/order?userId=' + userId + '&orderId=' + this.$route.query.orderId).then(response => {
console.log('order data', response.data);
this.orderItems = response.data.data[0].items;
});
}
}
Confirmation Page Requirements
The confirmation page requires recipient name, contact information, delivery address, and notes.
Database Update
Modify sql/collection/orders.js:
const mongoose = require('../db.js');
const Schema = mongoose.Schema;
const orderSchema = new Schema({
orderId: {type: String},
userId: {type: String},
status: {type: Number},
recipientName: {type: String},
phone: {type: String},
deliveryAddress: {type: String},
notes: {type: String},
items: {type: Array}
});
module.exports = mongoose.model('Order', orderSchema);
Order Creation Endpoint Update
Update routes/order.js:
router.get('/create', (req, res, next) => {
const orderData = JSON.parse(req.query.data);
const userId = req.query.userId;
const orderId = 'order_' + uuid.v1();
const orderItems = [];
orderData.forEach(item => {
orderItems.push({
productId: item.productId,
image: item.image,
name: item.name,
price: parseFloat(item.price),
quantity: parseInt(item.quantity)
});
});
sql.insert(Order, {
orderId: orderId,
userId: userId,
status: 0,
recipientName: '',
phone: '',
deliveryAddress: '',
notes: '',
items: orderItems
}).then(() => {
const deletionPromises = orderData.map(item => {
return sql.delete(Cart, { cartId: item.cartId });
});
return Promise.all(deletionPromises);
}).then(() => {
res.json({
code: '200',
message: 'Order created',
data: {
orderId: orderId
}
});
});
});
Address Management System
Implement routing in routes/address.js, collection in sql/collection/addresses.js, and registration in app.js.
Address Collection Schema
Create sql/collection/addresses.js:
const mongoose = require('../db.js');
const Schema = mongoose.Schema;
const addressSchema = new Schema({
addressId: {type: String},
userId: {type: String},
name: {type: String},
telephone: {type: String},
fullAddress: {type: String},
isDefault: {type: Number} // 1=default, 0=not default
});
module.exports = mongoose.model('Address', addressSchema);
Backend Address Creation Route
router.post('/create', (req, res, next) => {
let { userId, name, telephone, fullAddress, isDefault } = req.body;
isDefault = isDefault * 1 || 0;
const addressId = 'address_' + uuid.v1();
sql.insert(Address, { userId, name, telephone, fullAddress, isDefault, addressId }).then(() => {
res.json({
code: '200',
message: 'Address added successfully'
});
});
});
Frontend Address Creation Interface
Create views/address/create.vue and configure in router/index.js:
<template>
<div class="container">
<header class="page-header">Add Address</header>
<div class="main-content">
<van-address-edit
:area-list="areaData"
show-postal
show-delete
show-set-default
show-search-result
:search-result="searchResults"
area-columns-placeholder="['Select Province', 'Select City', 'Select District']"
@save="handleSave"
@delete="handleDelete"
@change-detail="handleChangeDetail"
/>
</div>
</div>
</template>
<script>
import Vue from 'vue'
import { AddressEdit, Toast } from 'vant'
import cityData from '@/utils/city'
Vue.use(AddressEdit)
export default {
data() {
return {
areaData: cityData,
searchResults: []
}
},
methods: {
handleSave(content) {
console.log(content);
Toast('Saved');
},
handleDelete() {
Toast('Deleted');
},
handleChangeDetail(val) {
}
}
}
</script>
<style lang="scss" scoped>
</style>
Address Submission
handleSave(content) {
console.log(content);
axios.post('/address/create', {
userId: localStorage.getItem('userId'),
name: content.name,
telephone: content.telephone,
fullAddress: content.province + content.city + content.district + content.detailAddress,
isDefault: content.isDefault
}).then(() => {
Toast('Address saved successfully');
});
},
Default Address and List Retrieval
router.get('/', (req, res, next) => {
const { userId, isDefault } = req.query;
const defaultFlag = isDefault * 1 || 0;
sql.find(Address, { userId, isDefault: defaultFlag }, { _id: 0 }).then(data => {
if (data.length === 0) {
res.json({
code: '30000',
message: 'No default address found'
});
} else {
res.json({
code: '200',
message: 'Addresses retrieved',
data: data
});
}
});
});
Order Confirmation Page Address Display
<template>
<div>
<ul v-if="hasDefaultAddress">
<li v-for="item in addressList" :key="item.addressId">
{{ item.name }} - {{ item.telephone }} - {{ item.fullAddress }}
</li>
</ul>
<div v-else>No default address
<router-link to="/createAddress">Add Address</router-link>
</div>
</div>
</template>
<script>
export default {
data() {
return {
orderItems: [],
addressList: [],
hasDefaultAddress: false
}
},
created() {
console.log(this.$route.query);
const userId = localStorage.getItem('userId');
axios.get('/order?userId=' + userId + '&orderId=' + this.$route.query.orderId).then(response => {
console.log('order data', response.data.data[0].items);
this.orderItems = response.data.data[0].items;
});
axios.get('/address?userId=' + userId + '&isDefault=1').then(response => {
console.log('addresses', response.data.data);
if (response.data.code === '30000') {
this.hasDefaultAddress = false;
} else {
this.hasDefaultAddress = true;
this.addressList = response.data.data;
}
});
}
}
</script>