A: hi! ~ Hello everyone, I am YK bacteria 🐷, a microsystem front-end ✨, love to think, love to summarize, love to record, love to share 🏹, welcome to follow me 😘 ~ [wechat account: Yk2012Yk2012, wechat public account: ykyk2012]
“This is the 12th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”
The address of the project: https://gitee.com/ykang2020/vue_shop
Today, WE continue to use Vue and Element to do the project of background management system and the commodity list function of commodity management module.
1. Introduction
The commodity management module is used to maintain commodity information on the e-commerce platform, including commodity types, parameters, pictures, details and other information. Through the commodity management module, the functions of adding, modifying, displaying and deleting commodities can be realized
The final effect picture is as follows:
2. To creategit
branch
Create a branch, goods_list, that writes lists of items
git checkout -b goods_list
Copy the code
git push -u origin goods_list
Copy the code
3. The initializationList.vue
Add a route
Similar to the previous steps, set up the basic structure
<template>
<div>
<! Breadcrumb navigation area -->
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/home' }">Home page</el-breadcrumb-item>
<el-breadcrumb-item>Commodity management</el-breadcrumb-item>
<el-breadcrumb-item>List of goods</el-breadcrumb-item>
</el-breadcrumb>
<! -- Card View area -->
<el-card>
<el-row :gutter="20">
<el-col :span="8">
<el-input placeholder="Please enter the content">
<el-button slot="append" icon="el-icon-search"></el-button>
</el-input>
</el-col>
<el-col :span="4">
<el-button type="primary">Add the goods</el-button>
</el-col>
</el-row>
</el-card>
</div>
</template>
Copy the code
4. List of goodstable
View the back-end interface for obtaining the list of items
4.1 Obtaining Data
The next step is to write the business logic for retrieving the data
data() {
return {
// Query the parameter object
queryInfo: {
query: ' '.pagenum: 1.pagesize: 10
},
// List of items
goodsList: [].// Total number of data items
total: 0}},created() {
this.getGoodsList()
},
methods: {
// Get the corresponding commodity list according to the pagination
async getGoodsList() {
const { data: result } = await this.$http.get('goods', { params: this.queryInfo })
if(result.meta.status ! = =200) {
return this.$message.error('Failed to get item list! ')}this.$message.success('Obtaining item list succeeded! ')
console.log(result.data)
this.goodsList = result.data.goods
this.total = result.data.total
}
}
Copy the code
4.2 Displaying Data
Present the data
<! Table table area -->
<el-table :data="goodsList" border stripe>
<el-table-column type="index"></el-table-column>
<el-table-column label="Trade Name" prop="goods_name"></el-table-column>
<el-table-column label=Commodity price (yuan) prop="goods_price" width="90px"></el-table-column>
<el-table-column label="Commodity weight" prop="goods_weight" width="70px"></el-table-column>
<el-table-column label="Creation time" prop="add_time" width="140px"></el-table-column>
<el-table-column label="Operation" width="130px">
<template>
<el-button type="primary" icon="el-icon-edit" size="mini"></el-button>
<el-button type="danger" icon="el-icon-delete" size="mini"></el-button>
</template>
</el-table-column>
</el-table>
Copy the code
4.3 Using global FiltersVue.filter
Custom formatting time
You can refer to this article [Vue] filter-vue.filter-moment.js blog.csdn.net/weixin_4497…
Main.js registers global filters
Vue.filter('dateFormat'.function (originVal) {
const dt = new Date(originVal)
const y = dt.getFullYear()
const m = (dt.getMonth() + 1 + ' ').padStart(2.'0') // If it is not two digits, fill it with 0
const d = (dt.getDate() + ' ').padStart(2.'0')
const hh = (dt.getHours() + ' ').padStart(2.'0')
const mm = (dt.getMinutes() + ' ').padStart(2.'0')
const ss = (dt.getSeconds() + ' ').padStart(2.'0')
return `${y}-${m}-${d} ${hh}:${mm}:${ss}`
})
Copy the code
<el-table-column label="Creation time" prop="add_time" width="140px">
<template slot-scope="scope">
{{scope.row.add_time | dateFormat}}
</template>
</el-table-column>
Copy the code
4.4 Effect Display
5. Product list paging management function
Just like we did before
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="queryInfo.pagenum"
:page-sizes="[5, 10, 15, 20]." "
:page-size="queryInfo.pagesize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
background
>
</el-pagination>
Copy the code
handleSizeChange(newSize) {
this.queryInfo.pagesize = newSize
this.getGoodsList()
},
handleCurrentChange(newPage) {
this.queryInfo.pagenum = newPage
this.getGoodsList()
}
Copy the code
6. Search and clear
<el-col :span="8">
<el-input placeholder="Please enter the content" v-model="queryInfo.query" clearable @clear="getGoodsList">
<el-button slot="append" icon="el-icon-search" @click="getGoodsList"></el-button>
</el-input>
</el-col>
Copy the code
7. According toID
Delete commodity data
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
@click="removeById(scope.row.goods_id)"
></el-button>
Copy the code
async removeById(id) {
const confirmResult = await this.$confirm('This operation will permanently delete this item. Do you want to continue? '.'tip', {
confirmButtonText: 'sure'.cancelButtonText: 'cancel'.type: 'warning'
}).catch(error= > error)
if(confirmResult ! = ='confirm') {
return this.$message.info('Cancelled delete! ')}const { data: result } = await this.$http.delete(`goods/${id}`)
if(result.meta.status ! = =200) {
return this.$message.error('Delete failed! ')}this.$message.success('Deleted successfully! ')
this.getGoodsList()
}
Copy the code
8. Product adding page
8.1 Jump to the page of adding goods through programmatic navigation
<el-button type="primary" @click="goAddPage">Add the goods</el-button>
Copy the code
goAddPage(){
this.$router.push('/goods/add')}Copy the code
Create the file goods/ add. vue to Add the routing rule
8.2 Rendering adds the basic structure of the page
<template>
<div>
<! Breadcrumb navigation area -->
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/home' }">Home page</el-breadcrumb-item>
<el-breadcrumb-item>Commodity management</el-breadcrumb-item>
<el-breadcrumb-item>Add the goods</el-breadcrumb-item>
</el-breadcrumb>
<! -- Card View area -->
<el-card>
<! -- Prompt area -->
<el-alert
title="Add Product information"
type="info"
center
show-icon
:closable="false"
></el-alert>
<! -- Step bar -->
<el-steps :space="200" :active="1" finish-status="success">
<el-step title="Done"></el-step>
<el-step title="In progress"></el-step>
<el-step title="Step 3"></el-step>
</el-steps>
</el-card>
</div>
</template>
Copy the code
8.3 Beautify step bar components
<! -- Step bar -->
<el-steps
:space="200"
:active="activeIndex"
finish-status="success"
align-center
>
<el-step title="Basic Information"></el-step>
<el-step title="Commodity parameters"></el-step>
<el-step title="Commodity attribute"></el-step>
<el-step title="Commodity picture"></el-step>
<el-step title="Product Content"></el-step>
<el-step title="Complete"></el-step>
</el-steps>
Copy the code
data() {
return {
activeIndex: 0}}Copy the code
8.4 apply colours to a drawingtab
Bar area
<! -- TAB field -->
<el-tabs :tab-position="'left'" style="height: 200px;">
<el-tab-pane label="Basic Information">The basic information</el-tab-pane>
<el-tab-pane label="Commodity parameters">Product parameters</el-tab-pane>
<el-tab-pane label="Commodity attribute">Commodity attribute</el-tab-pane>
<el-tab-pane label="Commodity picture">Commodity images</el-tab-pane>
<el-tab-pane label="Product Content">Commodity content</el-tab-pane>
</el-tabs>
Copy the code
8.5 Step andtab
Column data linkage
<el-steps :space="200" :active="activeIndex-0" finish-status="success" align-center>
Copy the code
<el-tabs :tab-position="'left'" style="height: 200px;" v-model="activeIndex">
Copy the code
activeIndex: '0'
Copy the code
8.6 Form Components
<el-form
:model="addForm"
:rules="addFormRules"
ref="addFormRef"
label-width="100px"
label-position="top"
>
Copy the code
8.7 UI Structure of the Basic Information Panel
<el-tab-pane label="Basic Information" name="0">
<el-form-item label="Trade Name" prop="goods_name">
<el-input v-model="addForm.goods_name"></el-input>
</el-form-item>
<el-form-item label="Commodity prices" prop="goods_price">
<el-input v-model="addForm.goods_price" type="number"></el-input>
</el-form-item>
<el-form-item label="Commodity weight" prop="goods_weight">
<el-input v-model="addForm.goods_weight" type="number"></el-input>
</el-form-item>
<el-form-item label="Quantity of Goods" prop="goods_number">
<el-input v-model="addForm.goods_number" type="number"></el-input>
</el-form-item>
<el-form-item label="Commodity Classification" prop="goods_cat">
<el-cascader
v-model="addForm.goods_cat"
:options="cateList"
:props="cateProps"
@change="handleChange"
></el-cascader>
</el-form-item>
</el-tab-pane>
Copy the code
addForm: {
goods_name: ' '.goods_price: 0.goods_weight: 0.goods_number: 0.// The category array to which the item belongs
goods_cat: []},addFormRules: {
goods_name: [{required: true.message: 'Please enter the name of the product'.trigger: 'blur'}].goods_price: [{required: true.message: 'Please enter commodity price'.trigger: 'blur'}].goods_weight: [{required: true.message: 'Please enter weight of goods'.trigger: 'blur'}].goods_number: [{required: true.message: 'Please enter quantity of goods'.trigger: 'blur'}].goods_cat: [{required: true.message: 'Please select product category'.trigger: 'blur'}},// List of goods by category
cateList: [].cateProps: {
expandTrigger: 'hover'.label: 'cat_name'.// See the attributes
value: 'cat_id'.// What value is selected
children: 'children' // Specify attributes to implement parent node nesting
}
Copy the code
// Get all commodity classification data
async getCateList() {
const { data: result } = await this.$http.get('categories')
if(result.meta.status ! = =200) {
return this.$message.error('Failed to get commodity classification data! ')}this.cateList = result.data
console.log(this.cateList)
},
// The cascade selector is selected
handleChange() {
console.log(this.addForm.goods_cat)
if (this.addForm.goods_cat.length ! = =3) {
this.addForm.goods_cat = []
}
}
Copy the code
8.8 Preventing TAB switching
<el-tabs :tab-position="'left'" v-model="activeIndex" :before-leave="beforeTabLeave">
Copy the code
beforeTabLeave(activeName, oldActiveName) {
if (oldActiveName === '0' && this.addForm.goods_cat.length ! = =3) {
this.$message.error('Please select the category first! ')
return false}}Copy the code
8.9 Obtaining Dynamic Parameter List Data
<el-tabs :tab-position="'left'" v-model="activeIndex" :before-leave="beforeTabLeave" @tab-click="tabClicked">
Copy the code
// Dynamic parameter list
manyTableData: []
Copy the code
async tabClicked() {
if (this.activeIndex === '1') {
const { data: result } = await this.$http.get(`categories/The ${this.cateId}/attributes`, {
params: { sel: 'many'}})if(result.meta.status ! = =200) {
return this.$message.error('Failed to get status parameter list! ')}console.log(result.data)
this.manyTableData = result.data
}
}
Copy the code
computed: {
cateId() {
if (this.addForm.goods_cat.length === 3) {
return this.addForm.goods_cat[2]}return null}}Copy the code
8.10 Drawing the check box of the Commodity Parameters panel
<! Render form item -->
<el-form-item
:label="item.attr_name"
v-for="item in manyTableData"
:key="item.attr_id"
>
<el-checkbox-group v-model="item.attr_vals">
<el-checkbox v-for="(cb, index) in item.attr_vals" :key="index" :label="cb" border></el-checkbox>
</el-checkbox-group>
</el-form-item>
Copy the code
async tabClicked() {
if (this.activeIndex === '1') {
const { data: result } = await this.$http.get(
`categories/The ${this.cateId}/attributes`,
{
params: { sel: 'many'}})if(result.meta.status ! = =200) {
return this.$message.error('Failed to get status parameter list! ')}console.log(result.data)
result.data.forEach(item= > {
item.attr_vals = item.attr_vals.length === 0 ? [] : item.attr_vals.split(' ')})this.manyTableData = result.data
}
}
Copy the code
.el-checkbox {
margin: 0 10px 0 0 ! important;
}
Copy the code
8.11 Obtaining Static Property List Data
<el-tab-pane label="Commodity attribute" name="2">
<el-form-item :label="item.attr_name" v-for="item in onlyTableData" :key="item.attr_id">
<el-input v-model="item.attr_vals"></el-input>
</el-form-item>
</el-tab-pane>
Copy the code
async tabClicked() {
if (this.activeIndex === '1') {
const { data: result } = await this.$http.get(
`categories/The ${this.cateId}/attributes`,
{
params: { sel: 'many'}})if(result.meta.status ! = =200) {
return this.$message.error('Failed to get status parameter list! ')}console.log(result.data)
result.data.forEach(item= > {
item.attr_vals =
item.attr_vals.length === 0 ? [] : item.attr_vals
})
this.manyTableData = result.data
} else if (this.activeIndex === '2') {
const { data: result } = await this.$http.get(
`categories/The ${this.cateId}/attributes`,
{
params: { sel: 'only'}})if(result.meta.status ! = =200) {
return this.$message.error('Failed to get status parameter list! ')}console.log(result.data)
result.data.forEach(item= > {
item.attr_vals =
item.attr_vals.length === 0 ? [] : item.attr_vals.split(' ')})this.onlyTableData = result.data
}
}
Copy the code
9. Picture uploading function
9.1 Initial Useupload
Upload component
<! -- Action indicates the API address of the upload.
<el-upload
:action="uploadURL"
:on-preview="handlePreview"
:on-remove="handleRemove"
list-type="picture"
>
<el-button size="small" type="primary">Click on the upload</el-button>
</el-upload>
Copy the code
// Upload the image URL
uploadURL: 'http://127.0.0.1:8888/api/private/v1/'
Copy the code
// Process the image preview effect
handlePreview() {},
// Handle the image removal operation
handleRemove() {}
Copy the code
9.2 manual forupload
Component bindingsheader
Request header
The el-Upload component does not use the AXIos we defined to send ajax requests
<el-upload
:action="uploadURL"
:on-preview="handlePreview"
:on-remove="handleRemove"
list-type="picture"
:headers="headerObj"
>
Copy the code
// The image upload component's header request object
headerObj: {
Authorization: window.sessionStorage.getItem('token')}Copy the code
9.3 listeningupload
The component’son-success
<el-upload
:action="uploadURL"
:on-preview="handlePreview"
:on-remove="handleRemove"
list-type="picture"
:headers="headerObj"
:on-success="handleSuccess"
>
Copy the code
addForm: {
goods_name: ' '.goods_price: 0.goods_weight: 0.goods_number: 0.// The category array to which the item belongs
goods_cat: [].// An array of images
pics: []}Copy the code
handleSuccess(responce) {
// console.log(responce)
// 1. Create an image information object
const picInfo = { pic: responce.data.temp_path }
// 2. Push the image information object into the PICS array
this.addForm.pics.push(picInfo)
}
Copy the code
9.4 listeningupload
The component’son-remove
// Handle the image removal operation
handleRemove(file) {
console.log(file)
// 1. Get the temporary path to the image to be deleted
const filePath = file.response.data.tmp_path
// 2. Find the index of this image from the pICS array
const i = this.addForm.pics.findIndex(x= > x.pic === filePath)
// 3. Call the array splice method to remove the image information object from the pICS array
this.addForm.pics.splice(i, 1)
console.log(this.addForm)
}
Copy the code
9.5 Image preview effect
<el-dialog title="Picture preview" :visible.sync="previewVisible" width="50%">
<img :src="previewPath" alt="" class="priviewImg">
</el-dialog>
Copy the code
previewPath: ' '.previewVisible: false
Copy the code
// Process the image preview effect
handlePreview(file) {
console.log(file)
this.previewPath = file.response.data.url
this.previewVisible = true
}
Copy the code
10. Product content
10.1 Installation and Configurationvue-quill-editor
Rich text editor
The installation runs on vue-quill-Editor 3.0.6
Github.com/surmon-chin…
// A detailed description of the product
goods_introduce: ' '
Copy the code
<! -- Rich text editing component -->
<quill-editor v-model="addForm.goods_introduce"></quill-editor>
<! Add product button -->
<el-button class="btnAdd" type="primary" @click="add">Add the goods</el-button>
Copy the code
.ql-editor {
min-height: 300px;
}
.btnAdd {
margin-top: 15px;
}
Copy the code
10.2 Form pre-validation
add() {
this.$refs.addFormRef.validate(valid= > {
if(! valid) {return this.$message.error('Fill out the necessary form items! ')}// Execute the added business logic
})
Copy the code
10.3 thegoods_cat
From an array to a string
Installation runs rely on LoDash for deep copy
import _ from 'lodash'
add() {
this.$refs.addFormRef.validate(valid= > {
if(! valid) {return this.$message.error('Fill out the necessary form items! ')}// Execute the added business logic
const form = _.cloneDeep(this.addForm)
form.goods_cat = form.goods_cat.join(', ')})}Copy the code
10.4 processingattrs
An array of
add() {
this.$refs.addFormRef.validate(valid= > {
if(! valid) {return this.$message.error('Fill out the necessary form items! ')}// Execute the added business logic
const form = _.cloneDeep(this.addForm)
form.goods_cat = form.goods_cat.join(', ')
// Handle dynamic parameters
this.manyTableData.forEach(item= > {
const newInfo = {
attr_id: item.attr_id,
attr_value: item.attr_vals.join(' ')}this.addForm.attrs.push(newInfo)
})
// Handle static attributes
this.onlyTableData.forEach(item= > {
const newInfo = {
attr_id: item.attr_id,
attr_value: item.attr_vals
}
this.addForm.attrs.push(newInfo)
})
form.attrs = this.addForm.attrs
})
}
Copy the code
10.5 Adding a Product Is Complete
add() {
this.$refs.addFormRef.validate(async valid => {
if(! valid) {return this.$message.error('Fill out the necessary form items! ')}// Execute the added business logic
const form = _.cloneDeep(this.addForm)
form.goods_cat = form.goods_cat.join(', ')
// Handle dynamic parameters
this.manyTableData.forEach(item= > {
const newInfo = {
attr_id: item.attr_id,
attr_value: item.attr_vals.join(' ')}this.addForm.attrs.push(newInfo)
})
// Handle static attributes
this.onlyTableData.forEach(item= > {
const newInfo = {
attr_id: item.attr_id,
attr_value: item.attr_vals
}
this.addForm.attrs.push(newInfo)
})
form.attrs = this.addForm.attrs
// Initiate a request to add an item
// The name of the item must be unique
const { data: result } = await this.$http.post('goods', form)
if(result.meta.status ! = =201) {
return this.$message.error('Failed to add item')}this.$message.success('Added item succeeded')
this.$router.push('/goods')})}Copy the code
11. List. Vue complete code
<template>
<div>
<! Breadcrumb navigation area -->
<el-breadcrumb separator-class="el-icon-arrow-right">
<el-breadcrumb-item :to="{ path: '/home' }">Home page</el-breadcrumb-item>
<el-breadcrumb-item>Commodity management</el-breadcrumb-item>
<el-breadcrumb-item>List of goods</el-breadcrumb-item>
</el-breadcrumb>
<! -- Card View area -->
<el-card>
<el-row :gutter="20">
<el-col :span="8">
<el-input
placeholder="Please enter the content"
v-model="queryInfo.query"
clearable
@clear="getGoodsList"
>
<el-button
slot="append"
icon="el-icon-search"
@click="getGoodsList"
></el-button>
</el-input>
</el-col>
<el-col :span="4">
<el-button type="primary" @click="goAddPage">Add the goods</el-button>
</el-col>
</el-row>
<! Table table area -->
<el-table :data="goodsList" border stripe>
<el-table-column type="index"></el-table-column>
<el-table-column label="Trade Name" prop="goods_name"></el-table-column>
<el-table-column
label=Commodity price (yuan)
prop="goods_price"
width="90px"
></el-table-column>
<el-table-column
label="Commodity weight"
prop="goods_weight"
width="70px"
></el-table-column>
<el-table-column label="Creation time" prop="add_time" width="140px">
<template slot-scope="scope">
{{ scope.row.add_time | dateFormat }}
</template>
</el-table-column>
<el-table-column label="Operation" width="130px">
<template slot-scope="scope">
<el-button
type="primary"
icon="el-icon-edit"
size="mini"
></el-button>
<el-button
type="danger"
icon="el-icon-delete"
size="mini"
@click="removeById(scope.row.goods_id)"
></el-button>
</template>
</el-table-column>
</el-table>
<el-pagination
@size-change="handleSizeChange"
@current-change="handleCurrentChange"
:current-page="queryInfo.pagenum"
:page-sizes="[5, 10, 15, 20]." "
:page-size="queryInfo.pagesize"
layout="total, sizes, prev, pager, next, jumper"
:total="total"
background
>
</el-pagination>
</el-card>
</div>
</template>
<script>
export default {
data() {
return {
// Query the parameter object
queryInfo: {
query: ' '.pagenum: 1.pagesize: 10
},
// List of items
goodsList: [].// Total number of data items
total: 0}},created() {
this.getGoodsList()
},
methods: {
// Get the corresponding commodity list according to the pagination
async getGoodsList() {
const { data: result } = await this.$http.get('goods', {
params: this.queryInfo
})
if(result.meta.status ! = =200) {
return this.$message.error('Failed to get item list! ')}this.$message.success('Obtaining item list succeeded! ')
console.log(result.data)
this.goodsList = result.data.goods
this.total = result.data.total
},
handleSizeChange(newSize) {
this.queryInfo.pagesize = newSize
this.getGoodsList()
},
handleCurrentChange(newPage) {
this.queryInfo.pagenum = newPage
this.getGoodsList()
},
async removeById(id) {
const confirmResult = await this.$confirm('This operation will permanently delete this item. Do you want to continue? '.'tip', {
confirmButtonText: 'sure'.cancelButtonText: 'cancel'.type: 'warning'
}).catch(error= > error)
if(confirmResult ! = ='confirm') {
return this.$message.info('Cancelled delete! ')}const { data: result } = await this.$http.delete(`goods/${id}`)
if(result.meta.status ! = =200) {
return this.$message.error('Delete failed! ')}this.$message.success('Deleted successfully! ')
this.getGoodsList()
},
goAddPage() {
this.$router.push('/goods/add')}}}</script>
<style scoped></style>
Copy the code
Branch of 12.git
operation
git add .
git commit -m "Complete product function development"
git push
git checkout master
git merge goods_list
git push
Copy the code
The address of the project: https://gitee.com/ykang2020/vue_shop
Finally, welcome to my column and make friends with YK bacteria