Vue实战电商系统-五商品管理

  • 商品管理
    • 1.新建goods_cate子分支并上传码云
    • 2.商品管理-商品分类
      • 1.新建文件并配置路由
      • 2.页面布局
      • 3.获取分类列表数据
      • 4.将数据渲染在树形表格控件中
      • 5.实现分页
      • 6.添加分类
      • 7.删除分类
      • 8.编辑分类
    • 3.商品管理-分类参数
      • 1.页面布局
      • 2.获取所有分类参数列表(级联选择器)
      • 3.Tabs标签页
      • 4.参数数据获取
      • 5.数据渲染
      • 6.添加动态参数/静态属性
      • 7.编辑动态参数/静态属性
      • 8.删除动态参数/静态属性
      • 9.渲染动态参数下的可选项
      • 10.增加动态参数下的可选项
      • 11.删除动态参数下的可选项
      • 12.功能优化
      • 13.上传代码
    • 4.商品管理-商品列表
      • 1.创建新分支并推送到码云
      • 2.页面布局和数据渲染
      • 3.自定义格式化时间的全局过滤器
      • 4.添加商品
      • 5.添加富文本编辑器
      • 6.goods_cat类型问题
      • 7.attrs属性的处理

商品管理

1.新建goods_cate子分支并上传码云

git branch
git checkout -b goods_cate
git push -u origin goods_cate

2.商品管理-商品分类

1.新建文件并配置路由

components/goods/Cate.vue

2.页面布局

<template><div><!-- 面包屑导航区域 --><el-breadcrumb separator="/"><el-breadcrumb-item :to="{ path: '/home' }">首页</el-breadcrumb-item><el-breadcrumb-item>商品管理</el-breadcrumb-item><el-breadcrumb-item>商品分类</el-breadcrumb-item></el-breadcrumb><!-- 卡片区域 --><el-card><!-- 添加分类按钮 --><el-row><el-col :span="4"><el-button type="primary">添加分类</el-button></el-col></el-row><!-- 表格数据区域 --><el-table :data="userlist" style="width: 100%" border stripe :cell-style="rowClass" :header-cell-style="headClass"><el-table-column type="index" label="#"></el-table-column><el-table-column prop="username" label="分类名称"></el-table-column><el-table-column prop="email" label="是否有效"></el-table-column><el-table-column prop="mobile" label="排序"></el-table-column><el-table-column label="操作" width="180px"><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">删除</el-button></template></el-table-column></el-table><!-- 分页区域 --><el-pagination@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="currentPage4":page-sizes="[100, 200, 300, 400]":page-size="100"layout="total, sizes, prev, pager, next, jumper":total="400"></el-pagination></el-card></div>
</template>

3.获取分类列表数据

async getCateList() {const { data: res } = await this.$http.get('categories', { params: this.queryInfo })if (res.meta.status !== 200) return this.$message.error('获取分类列表信息失败!')this.catelist = res.data.resultconsole.log(this.catelist)this.total = res.data.total
},

4.将数据渲染在树形表格控件中

因为elementUI并没有提供树形表格控件,所以需要用到第三方组件库
vue可视化面板中安装一个新的运行依赖vue-table-with-tree-grid。如下图:

接着在main.js导入新依赖并全局注册为组件

// 导入第三方的树形表格控件
import TreeTable from 'vue-table-with-tree-grid'
...
Vue.component('tree-table',TreeTable)

接着按照第三方组件的API文档以及示例代码照着写就完事了:

<!-- 表格数据区域 -->
<tree-table
:data="catelist"
:columns="columns"
:selection-type="false"
:expand-type="false"
:show-index="true"
index-text="#"
border
:show-row-hover="false"><!-- 是否有效列的模板 --><template slot="isok" slot-scope="scope"><i class="el-icon-success" v-if="scope.row.cat_deleted === false" style="color: lightgreen;"></i><i class="el-icon-error" v-else style="color: red;"></i></template><!-- 排序列的模板 --><template slot="order" slot-scope="scope"><el-tag size="mini" v-if="scope.row.cat_level === 0">一级</el-tag><el-tag size="mini" type="success" v-else-if="scope.row.cat_level === 1">二级</el-tag><el-tag size="mini" type="warning" v-else>三级</el-tag></template><!-- 操作列的模板 --><template slot="opt" 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">删除</el-button></template>
</tree-table>
...
columns: [
{label: '分类名称',prop: 'cat_name'
},
{label: '是否有效',// 表示将当前列自定义为模板列type: 'template',// 表示当前这一列使用的自定义模板的名称template: 'isok'
},
{label: '排序',type: 'template',template: 'order'
},
{label: '操作',type: 'template',template: 'opt'
}
]

5.实现分页

<!-- 分页区域 -->
<el-pagination@size-change="handleSizeChange"@current-change="handleCurrentChange":current-page="queryInfo.pagenum":page-sizes="[3, 5, 10, 15]":page-size="queryInfo.pagesize"layout="total, sizes, prev, pager, next, jumper":total="total">
</el-pagination>
...
// 监听pagesize改变事件
handleSizeChange(newSize) {this.queryInfo.pagesize = newSizethis.getCateList()
},
// 监听页码值改变的函数
handleCurrentChange(newPage) {this.queryInfo.pagenum = newPagethis.getCateList()
}

6.添加分类

在这里插入代码片

碰到级联选择器占满整个屏幕(高度太大)并且数据显示不全时,添加一个样式即可:.el-cascader-panel { height: 300px; }

级联选择器默认只能选中最小层的选项,也就是说无法选择那些父级选项。要实现都可以选择的功能的话,添加一个属性:change-on-select。新版本在选项前会出现一个圆圈。

7.删除分类

删除,编辑这些功能逻辑和之前的用户管理,角色管理都类似。

// 删除分类
async deleteCateById(id) {const confirmResult = await this.$confirm('确定将此分类删除吗', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'}).catch(err => err)console.log(confirmResult)if (confirmResult !== 'confirm') {return this.$message.info('已取消删除')}const { data: res } = await this.$http.delete('categories/' + id)console.log(res)if (res.meta.status !== 200) return this.$message.error('删除分类失败!')this.$message.success('删除分类成功!')this.getCateList()
},

8.编辑分类

// 展开编辑分类信息的对话框
async showEditCateDialog(id) {const { data: res } = await this.$http.get('categories/' + id)console.log(res)this.editCateForm = res.datathis.editCatedialogVisible = !this.editCatedialogVisible
},
// 监听编辑分类对话框的关闭事件
editCatesDialogClosed() {this.$refs.editCateFormRef.resetFields()
},
editCate() {console.log(this.editCateForm)this.$refs.editCateFormRef.validate(async valid => {if (!valid) return// 可以发起添加请求const { data: res } = await this.$http.put('categories/' + this.editCateForm.cat_id, { cat_name: this.editCateForm.cat_name })if (res.meta.status !== 200) {this.$message.error('更新分类信息失败')}// 更新成功之后关闭对话框this.editCatedialogVisible = !this.editCatedialogVisible// 更新成功之后重新获取用户信息列表this.getCateList()// 修改成功后的提示信息this.$message.success('更新用户信息成功!')})
}

3.商品管理-分类参数

商品的参数可以大致分为两类:静态参数动态参数。例如一台手机,静态参数就有品牌,上市时间,型号等等,动态参数就有颜色,存储容量(8+128GB,8+256GB)等等。

1.页面布局

2.获取所有分类参数列表(级联选择器)

data() {return {// 所有的分类数据列表cateList: [],// 指定级联选择器的配置对象cascaderProps: {value: 'cat_id',label: 'cat_name',children: 'children',expandTrigger: 'hover'},// 选中的父级分类的id数组selectedKeys: []}},created() {this.getCateList()},methods: {// 获取所有的分类数据列表async getCateList() {const { data: res } = await this.$http.get('categories')if (res.meta.status !== 200) return this.$message.error('获取商品分类失败!')this.cateList = res.dataconsole.log(this.cateList)},// 监听级联菜单选择项改变事件cateChanged() {console.log(this.selectedKeys)// 如果selectedKeys数组中的length > 0,证明选中了父级分类// 反之就说明没有选择任何父级分类if (this.selectedKeys.length > 0) {} else {}}}

注意,这里的级联菜单只允许为第三级分类设置相关参数,因此在监听菜单选择项改变事件中,如果selectedKeys的长度不为3,那么就说明选择不合法,就需要重置选项

实现代码如下所示:

// 将一级二级菜单选项设置为不可选
if (this.selectedKeys.length !== 3) {this.$message.warning('注意:只允许为第三级分类设置相关参数!')this.selectedKeys = []
}

3.Tabs标签页

在标签页中的添加参数添加属性两个按钮会根据级联菜单中的选项是否被选择而变化(按钮可用,按钮不可用)。

<el-button type="primary" size="medium" :disabled="isBtnDisable">添加参数</el-button>
...
computed: {// 如果按钮需要被禁用,返回true;否则就返回falseisBtnDisable() {if (this.selectedKeys.length !== 3) {return true}return false}}

4.参数数据获取

// 监听级联菜单选择项改变事件
cateChanged() {console.log(this.selectedKeys)// 将一级二级菜单选项设置为不可选if (this.selectedKeys.length !== 3) {this.$message.warning('注意:只允许为第三级分类设置相关参数!')this.selectedKeys = []}// 已经正确地选择了三级分类// 在级联菜单选项改变时请求数据// 根据所选分类的id和所处面板获取对应的数据this.getParamsData()
},
// Tab标签点击事件地处理函数
handleTabClick() {console.log(this.activeName)// 在动态参数和静态属性面板之间切换是也要动态调用方法获取数据this.getParamsData()
},
// 获取参数列表数据
async getParamsData() {const { data: res } = await this.$http.get(`categories/${this.cateId}/attributes`, { params: { sel: this.activeName } })if (res.meta.status !== 200) return this.$message.error('获取参数/属性失败!')console.log(res)// 在获取到数据后要进行判断然后再渲染到对应的面板中去// 如果获取到的数据 属于 动态参数if (this.activeName === 'many') {this.manyTableData = res.data} else {// 如果获取到的数据 属于 静态属性this.onlyTableData = res.data}
}

5.数据渲染

<el-tabs v-model="activeName" @tab-click="handleTabClick">
<el-tab-pane label="动态参数" name="many"><el-button type="primary" size="medium" :disabled="isBtnDisable">添加参数</el-button><!-- 动态参数数据表格 --><el-table :data="manyTableData" border stripe :cell-style="rowClass" :header-cell-style="headClass"><el-table-column type="expand"></el-table-column><el-table-column type="index" label="#"></el-table-column><el-table-column prop="attr_name" label="参数名称"></el-table-column><el-table-column label="操作"><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">删除</el-button></template></el-table-column></el-table>
</el-tab-pane>
<el-tab-pane label="静态属性" name="only"><el-button type="primary" size="medium" :disabled="isBtnDisable">添加属性</el-button><!-- 静态属性数据表格 --><el-table :data="onlyTableData" border stripe :cell-style="rowClass" :header-cell-style="headClass"><el-table-column type="expand"></el-table-column><el-table-column type="index" label="#"></el-table-column><el-table-column prop="attr_name" label="属性名称"></el-table-column><el-table-column label="操作"><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">删除</el-button></template></el-table-column></el-table>
</el-tab-pane>
</el-tabs>

6.添加动态参数/静态属性

添加动态参数/静态属性时的对话框仅仅是提示文字不同,样式基本相同因此只需要共用一个即可。

<el-dialog
:title="'添加' + dialogTitle"
:visible.sync="addParamsdialogVisible"
width="50%"
@close="addParamsdialogClosed">
<el-form :model="addParamsForm" :rules="addParamsFormrules" ref="addParamsFormRef" label-width="7px"><el-form-item :label="dialogTitle + '名称'" prop="attr_name"><el-input v-model="addParamsForm.attr_name"></el-input></el-form-item>
</el-form>
<span slot="footer" class="dialog-footer"><el-button @click="addParamsdialogVisible = false">取 消</el-button><el-button type="primary" @click="addParam">确 定</el-button>
</span>
</el-dialog>
...
// 增加动态参数/静态属性
addParam() {console.log(this.addParamsForm)this.$refs.addParamsFormRef.validate(async valid => {if (!valid) return// 可以发起添加请求const { data: res } = await this.$http.post(`categories/${this.cateId}/attributes`, { attr_sel: this.activeName, attr_name: this.addParamsForm.attr_name })console.log(res)if (res.meta.status !== 201) {this.$message.error('添加' + this.dialogTitle + '失败')}this.$message.success('添加' + this.dialogTitle + '成功!')// 添加成功之后关闭对话框this.adddialogVisible = !this.adddialogVisible// 添加成功之后重新获取用户信息列表this.getParamsData()})this.addParamsdialogVisible = !this.addParamsdialogVisible
},
// 监听添加动态参数/静态属性的对话框关闭事件
addParamsdialogClosed() {this.$refs.addParamsFormRef.resetFields()
},
...
computed: {// 获取当前添加动态参数还是静态属性
dialogTitle() {if (this.activeName === 'many') {return '动态参数'} else {return '静态属性'}
}
}

7.编辑动态参数/静态属性

// 显示编辑动态参数/静态属性的对话框
async showeditParamsdialog(attrId) {console.log(attrId)// 根据角色id查询该角色const { data: res } = await this.$http.get(`categories/${this.cateId}/attributes/` + attrId)if (res.meta.status !== 200) return this.$message.error('拉取参数信息失败')this.editParamsForm = res.datathis.editParamsdialogVisible = !this.editParamsdialogVisible
},
// 编辑动态参数/静态属性
editParam() {this.$refs.editParamsFormRef.validate(async valid => {if (!valid) return// 可以发起添加请求const { data: res } = await this.$http.put(`categories/${this.cateId}/attributes/${this.editParamsForm.attr_id}`, {attr_name: this.editParamsForm.attr_name,attr_sel: this.activeName})if (res.meta.status !== 200) {this.$message.error('更新参数信息失败')}// 更新成功之后关闭对话框this.editParamsdialogVisible = !this.editParamsdialogVisible// 更新成功之后重新获取用户信息列表this.getParamsData()// 修改成功后的提示信息this.$message.success('更新参数信息成功!')})
},
// 监听编辑动态参数/静态属性的对话框关闭事件
editParamsdialogClosed() {this.$refs.editParamsFormRef.resetFields()
}

8.删除动态参数/静态属性

async deleteParamsById(attrId) {const confirmResult = await this.$confirm('确定将此' + this.dialogTitle + '删除吗', '提示', {confirmButtonText: '确定',cancelButtonText: '取消',type: 'warning'
}).catch(err => err)
console.log(confirmResult)
if (confirmResult !== 'confirm') {return this.$message.info('已取消删除')
}
const { data: res } = await this.$http.delete(`categories/${this.cateId}/attributes/${attrId}`)
console.log(res)
if (res.meta.status !== 200) return this.$message.error('删除' + this.dialogTitle + '失败')
this.$message.success('删除' + this.dialogTitle + '成功')
// 重新拉取用户信息列表
this.getParamsData()
}

9.渲染动态参数下的可选项

<template slot-scope="scope"><el-tag v-for="(item, index) in scope.row.attr_vals" :key="index" closable>{{ item }}</el-tag>
</template>

10.增加动态参数下的可选项

async handleInputConfirm(row) {// 如果在输入时误打了空格
if (row.inputValue.trim().length === 0) {row.inputValue = ''row.inputVisible = !row.inputVisible
} else {// 如果没有return说明用户输入了有效内容,此时// 当文本框失去焦点时要将文本框重新变为按钮并且将内容生成Tag标签再清除row.attr_vals.push(row.inputValue.trim())row.inputValue = ''row.inputVisible = !row.inputVisible// 需要发起请求来保存这一次操作const { data: res } = await this.$http.put(`categories/${this.cateId}/attributes/${row.attr_id}`, {attr_name: row.attr_name,attr_sel: row.attr_sel,attr_vals: row.attr_vals.join(' ')})console.log(res)if (res.meta.status !== 200) return this.$message.error('更新' + this.dialogTitle + '失败')this.$message.success('更新' + this.dialogTitle + '成功')
}
}

在这里实际开发的话应该是先要将数据更新到数据库,如果发送的请求返回正确校验码再更新页面上的数据。如下代码:

const { data: res } = await this.$http.put(`categories/${this.cateId}/attributes/${row.attr_id}`, {attr_name: row.inputValue.trim(),attr_sel: row.attr_sel
})
console.log(res)
if (res.meta.status !== 200) return this.$message.error('更新' + this.dialogTitle + '失败')
this.$message.success('更新' + this.dialogTitle + '成功')
row.attr_vals.push(res.data.attr_name)
row.inputValue = ''
row.inputVisible = !row.inputVisible

11.删除动态参数下的可选项

// 动态参数下的可选项标签的点击删除事件
async handleClose(index, row) {row.attr_vals.splice(index, 1)const { data: res } = await this.$http.put(`categories/${this.cateId}/attributes/${row.attr_id}`, {attr_name: row.attr_name,attr_sel: row.attr_sel,attr_vals: row.attr_vals.join(' ')})console.log(res)if (res.meta.status !== 200) return this.$message.error('删除失败')this.$message.success('删除成功')
},

12.功能优化

因为在级联菜单中进行选择时,是不允许选择非三级菜单的,但是实际如果选择了二级菜单,级联选择器的内容会被清空(没问题),添加按钮会被禁用(没问题),但是数据表格仍然会被渲染出来。因此需要做一下清除:

this.manyTableData = []
this.onlyTableData = []

13.上传代码

4.商品管理-商品列表

1.创建新分支并推送到码云

git checkout -b goods_list
git push -u origin goods_list

2.页面布局和数据渲染

页面布局和数据渲染同上面商品分类以及分类参数基本相同。

3.自定义格式化时间的全局过滤器

在商品列表中的创建时间这一列中,数据是以时间戳(单位为毫秒)的,因此可以在全局自定义一个格式化时间的过滤器。
main.js

Vue.filter('dateFormat', function(originVal) {const dt = new Date(originVal)const year = dt.getFullYear()const month = (dt.getMonth() + 1 + '').padStart(2, '0')const day = (dt.getDate() + '').padStart(2, '0')const hour = (dt.getHours() + '').padStart(2, '0')const minute = (dt.getMinutes() + '').padStart(2, '0')const second = (dt.getSeconds() + '').padStart(2, '0')return `${year}-${month}-${day} ${hour}:${minute}:${second}`
})

在页面中插入模板字符串:

<el-table-column prop="add_time" label="创建时间" width="140px"><template slot-scope="scope">{{scope.row.add_time | dateFormat}}</template>
</el-table-column>

4.添加商品

添加商品功能模块和之前的不一样,不再是弹窗式的对话框了(因为商品信息比较多),而是跳转到另一个页面

5.添加富文本编辑器

在vue项目中的富文本编辑器叫做vue-quill-editor。配置过程如下:

1.首先在vue项目可视化面板中选择依赖-安装新依赖-运行依赖并搜索vue-quill-editor然后安装

2.接着进行全局注册,然后在页面上即可使用。具体步骤在vue-quill-editor使用文档说明。
在入口文件main.js中导入:

// 导入富文本编辑器
import VueQuillEditor from 'vue-quill-editor'
// 导入富文本编辑器对应的样式
import 'quill/dist/quill.core.css'
import 'quill/dist/quill.snow.css'
import 'quill/dist/quill.bubble.css'Vue.use(VueQuillEditor)

在页面上对应的组件代码为:

<!-- 富文本编辑器区域 -->
<quill-editorref="myQuillEditor"// 内容的绑定v-model="addGoodsForm.goods_introduce":options="editorOption"@blur="onEditorBlur($event)"@focus="onEditorFocus($event)"@ready="onEditorReady($event)"
>
</quill-editor>

注意,如果富文本编辑器的文本输入区域高度不合适,可以自行指定。具体实现如下,注意类名ql-editor

.ql-editor {// 设置min-height: 300px;
}

6.goods_cat类型问题

级联选择器中,要求绑定的数据类型是数组,但是在发送添加商品的请求的时候又要求类型是字符串。因此两者存在矛盾,也就是说当在发送添加商品的请求前对goods_cat进行数据类型转换的同时,因为双向绑定所以会导致级联选择器的报错。

解决办法:深度拷贝。也就是说在发送请求时,转换数据类型不再在原来的数据对象上转换,而是拷贝一个一模一样的新对象进行类型转换。

首先在vue可视化面板中添加一个运行依赖lodash

接着在vue中导入并使用了:

import _ from 'lodash'
...
const form = _.cloneDeep(this.addGoodsForm)
form.goods_cat = form.goods_cat.join(',')

7.attrs属性的处理

addGoods() {// 查看富文本编辑器是否与对应属性值绑定console.log(this.addGoodsForm.goods_introduce)this.$refs.addGoodsFormRef.validate(async valid => {if (!valid) {return this.$message.error('请填写必要的表单项')}// 执行添加的逻辑操作// 执行添加前需要将goods_cat从数组转换为字符串(接口要求)// 深度拷贝 lodash cloneDeep(Obj)const form = _.cloneDeep(this.addGoodsForm)form.goods_cat = form.goods_cat.join(',')// 处理动态参数this.manyTableData.forEach(item => {const newInfo = { attr_id: item.attr_id, attr_value: item.attr_vals.join(' ') }this.addGoodsForm.attrs.push(newInfo)})// 处理静态属性this.onlyTableData.forEach(item => {const newInfo = { attr_id: item.attr_id, attr_value: item.attr_vals }this.addGoodsForm.attrs.push(newInfo)})form.attrs = this.addGoodsForm.attrsconsole.log(form)// 发起添加商品的请求const { data: res } = await this.$http.post('goods', form)console.log(res)if (res.meta.status !== 201) return this.$message.error('添加商品失败!')this.$message.success('添加商品成功!')// 跳转到商品列表页面this.$router.push('/goods')})
}

Vue实战电商系统-五商品管理相关推荐

  1. 基于VUE的电商系统的设计与实现

    随着移动互联网技术和计算机技术的不断发展,电子商务已经成为社会发展的潮流,通过电子商务系统商品信息交流变的更加方便.面对高速发展的电子商务,电商系统如雨后春笋不断的涌现.利用电商系统,企业销售可以足不 ...

  2. HH SaaS电商系统的商品系统设计

    文章目录 商品信息结构 商品信息总结构 商品信息结构图 发布商品 商品类型 虚拟商品 服务商品 为什么服务商品要分类 前端根据服务商品类型来设计不同的界面和交互 订单状态和服务类型有关 商品档案上下架 ...

  3. 电商系统的商品库存管理

    基于数组+面向对象的商品信息管理系统 面向对象程序设计 完成一个电商系统的商品库存管理的系统 包含两个类: 商品类(编号,名称,类别,单价,库存量,生产地) 商品管理类 管理类中需完成功能: 商品添加 ...

  4. 通过Dapr实现一个简单的基于.net的微服务电商系统(五)——一步一步教你如何撸Dapr之状态管理...

    状态管理和上一章的订阅发布都算是Dapr相较于其他服务网格框架来讲提供的比较特异性的内容,今天我们来讲讲状态管理. 目录: 一.通过Dapr实现一个简单的基于.net的微服务电商系统 二.通过Dapr ...

  5. 电商系统搭建(商品订单模块)

    借助直播的东风,电商系统正在飞速发展,那么如何从0开始搭建电商系统. 这篇文章就介绍一下怎么简单的搭建一个电商系统,首先从电商系统的核心(订单)来开讲. 数据结构设计 商品表,商品细节表,订单表,订单 ...

  6. 电商系统,商品属性表和功能设计,可用于各种实体的属性

    简介 定义一种通用的属性体系,可以表示任何实体的属性,同时也像数据库列一样,可以为属性指定数据类型.在电商系统中, 每个商品都有多个属性,并且这些属性不能提前设定,它们以无模式的key/value形式 ...

  7. [Vue.js]实战 -- 电商项目(五)

    参数管理 参数管理概述 商品参数用于显示商品的固定的特征信息,可以通过电商平台商品详情页面直观的看到 商品分类选择 选择商品分类 页面布局 <div><!-- 面包屑导航区域 --& ...

  8. 9.1黑马Vue电商后台管理系统商品管理模块完善:编辑商品的功能

    在原视频中,老师跳过了这个功能,我觉得自己去实现也可以锻炼自己,于是自己补充了编辑功能 同用户管理,权限管理等之前各个模块的编辑功能不同,因为商品具有很多可编辑的选项,所以选择像添加商品一样,单独放在 ...

  9. [Vue]实战---电商项目(项目的概述及初始化)【一】

    项目实战 项目目录 项目概述 项目初始化 登录/退出功能 主页布局 用户管理模块 权限管理模块 分类管理模块 参数管理模块 商品管理模块 订单管理模块 数据统计模块 项目概述 电商项目基本业务概述 电 ...

最新文章

  1. 【Tensorflow】解决No module named ‘matplotlib‘/‘pandas‘
  2. Example-Based Facial Rigging
  3. 用XAML做网页!!—广告展示区
  4. cloud 调用列表并返回数据操作代码
  5. 如何在计算机管理路由器,如何在电脑上管理自家的wifi ? | 192路由网
  6. 2021学习 - OEM,ODM,OBM,JDM和白牌化
  7. 终于懂得孤独是躲不开的单行道
  8. 医药产品经理ims数据分析
  9. vps和云主机哪个好
  10. vue移动端用什么数据可视化插件_vue框架大屏可视化
  11. 新零售的坑,社交流量怎么填?
  12. 几种颜色单位设置(颜色设置)
  13. python爬取凤凰新闻网_python3.6爬取凤凰网新闻-爬虫框架式思维
  14. JavaScript网页特效-“渔夫打鱼晒网”程序设计
  15. cmd命令和终端怎么实现切换目录
  16. springboot切面AOP拦截父类或接口中标记注解的方法
  17. Note++ 常用功能高级用法
  18. 结束任务管理器快捷键是什么?怎么结束电脑程序运行?
  19. 知识补充----Java
  20. 优化用电,安全省心,同为(TOWE)智能循环定时桌面PDU插座APZ-1013DX

热门文章

  1. div中内容水平垂直居中
  2. 通过GRUB引导安装Red Flag系统
  3. PHP- 周易五格计算算法
  4. 很实用的一款数据恢复软件 easyrecovery 分享给大家
  5. Light Propagation Volumes in CryEngine 3
  6. 快捷键及Dos命令学习总结
  7. 最小生成树:克鲁斯卡尔算法+普里姆算法
  8. 如何快速判断一个数是否为16的倍数
  9. 网络终极卫士 NetworkKiller V1.5
  10. 概率论与数理统计之正态分布