# Vue3-admin-nyist **Repository Path**: zsj1210/vue3-admin-nyist ## Basic Information - **Project Name**: Vue3-admin-nyist - **Description**: vue3-admin-nyist商品后台管理系统 - **Primary Language**: TypeScript - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2022-11-09 - **Last Updated**: 2022-11-17 ## Categories & Tags **Categories**: Uncategorized **Tags**: vue3, TypeScript, vite, element-plus, Pinia ## README ## 项目流程-记录项目开发过程 - day01 - 项目接口: * 商品管理接口 http://39.98.123.211:8510/swagger-ui.html * 权限接口 http://39.98.123.211:8170/swagger-ui.html - 书写登录的api接口及类型 * `api/user.ts` * axios.get()方法要书写一个泛型,代表当前请求的数据类型,`axios.get()` - 重写登录逻辑 * 重写store中的login方法 * 在方法中发送真实的请求,并且把token保存起来 - 重写获取用户信息逻辑 * 在store中重写getInfo方法,变成真正的请求 * 在请求头中配置token的请求头,才能真正的把请求发送成功 * 注意:在非组件中使用pinia的hooks的时候,比如传递pinia作为参数 - 重写退出登录逻辑 * 在store中重新书写一个logout方法,不再直接使用之前的reset方法 * logout方法中要发送请求,然后成功之后,调用reset方法 * 在NavBar组件中,把退出登录的按钮逻辑的调用方法改为logout - 在pinia中设置完整的用户信息 * 之前的用户信息是只有name和avatar直接设置在state中,我们发送完真实的请求之后,得到的有完整的用户信息对象 * 删掉之前的name和avatar属性,设置一个新的userInfo属性,并且要去类型中修改类型 * 当获取用户信息完成之后,直接把得到的信息赋值给state中的userInfo * 当数据结构发生变化的时候,我们需要去修改获取数据的地方 1. 在store的reset方法中,不再重置name和avatar,而是直接重置userInfo 2. 在permission中,判断是否获取用户信息的时候,需要添加userInfo属性 3. 在home页展示用户信息的时候,需要添加userInfo属性 4. 在layOut中的NavBar组件中,展示的头像和用户名也要添加userInfo属性 - 配置商品管理中的路由表 * 首先书写一个/product的一级路由,这个一级路由负责加载layout主体 * 在配置4个二级路由,负责展示4个功能组件 * 在一级路由中配置meta的icon和title,在侧边栏中可以展示菜单 * 在二级路由中也要配置meta的title,用在在侧边栏展示菜单 * 侧边栏的菜单展示是去userInfoStore中读取的menuRoutes属性,所以我们需要获取到路由表,设置给menuRoutes属性即可 * 书写 attr trademark sku spu 4个组件 - 品牌管理静态完成 * 注意点1:tabel组件中 table-column组件的prop属性 label属性 * 注意点2:table-column组件插槽的使用及作用域参数 row和$index * 注意点3:pagination组件的使用,及常用属性 - day02 - 品牌分页列表的api书写 * 书写api的时候,要书写返回值和参数的类型 * 定义类型要分开定义,最后再合成一个,并且每一个类型都要暴露出去,方便再其他位置使用 - 品牌分页列表的store的书写 * 在state中定义组件中需要的数据,并且要给state设置类型 * 在actions中要定义一个发送请求的函数,拿到返回值要把里边的需要的值设置给state - 组件中拿到品牌的数据并渲染 * 通过store拿到actions中的方法,封装一个请求函数,在初始化的时候请求 * 在请求函数中,如果请求完成,则把请求的结果交给我们预先定义好的ref对象数据 * 记得给ref对象数据设置类型 - 品牌分页列表的页码书写 * 因为书写的页码组件内部已经和外部的数据双向绑定了 * 我们只需要watch监听页码内部数据的改变,然后重新发送请求即可 - 添加品牌的弹窗 * 使用dialog组件,进行制作弹窗 * 弹窗内部需要书写表单元素,一个是input 一个是upload * upload组件使用的时候,需要拿到逻辑代码和样式代码才可以使用 - 修改的逻辑分析 * 修改逻辑和新增逻辑是一样的,并且使用的弹窗也是一样的 * 我们需要定义一个ref数据,和弹窗内的input和upload进行双向绑定 * 新增的时候,默认数据为空 * 修改的时候,需要拿到当前按钮所在行的数据,并设置给我们定义的ref数据 * 最后根据ref数据中是否有id,来判断当前是新增还是修改(因为id只能是后端添加并反馈给前端的) - 修改和添加按钮的一些小问题 1. 点击修改的时候,数据已经回填了,但是一旦修改输入框,发现展示的数据也修改了 + 解决:不要直接把当前按钮所在的数据赋值给ref对象数据,而是使用拷贝 2. 当点击完修改以后,再点击新增,还会残留修改的数据 + 解决:新增的时候,先清空ref对象的数据,在打开弹窗 - 上传图片预览功能 1. 上传图片预览功能是自带的,我们需要把upload组件中的action属性的地址改为上传地址 2. 在上传图片的传递进去组件内的成功回调函数中,我们可以拿到第一个参数response,里边有一个data属性,只为上传后的图片地址 - 更新和新增品牌完成 * 封装新增和更新的api * 当点击确定的时候,判断当前是新增还是更新,然后调用对应的api * 当点击确定后,要重新发送请求和关闭弹窗 - 表单单独校验 * Form 组件提供了表单验证的功能 * 只需为 rules 属性传入约定的验证规则 * 并将 form-Item 的 prop 属性设置为需要验证规则中的key即可 - 整体校验 * 首先给form组件设置一个model属性,值为当前表单收集的值组成的对象 * 给form组件设置一个ref属性,然后我们在逻辑中通过ref得到这个form组件 * 在整体提交事件函数中,调用这个form组件的validate方法,校验是异步的,我们需要使用await等待返回布尔值的结果 * 因为校验失败会返回失败的promise,所以我们需要进行异常处理 * 每次打开弹窗先关闭之前的校验提示,使用表单组件的clearValidate方法 - 删除品牌功能 * 封装删除品牌的api * 点击删除的时候调用删除接口 * 重新发送请求 - 删除确认气泡框 * 找到删除确认气泡框的组件,把按钮放在气泡框中 * 气泡框组件有一个confirm事件,当点击确认的时候触发 * 可以把之前写在删除中的事件函数,直接写在confirm事件中即可 - 三级分类的视图 * 因为三级分类功能要复用,所以我们封装一个公共组件,放在components文件夹中,然后全局注册 * 分装三级分类的请求api函数 * 书写三级分类的store + 数据有三级分类的每一个分类列表,和每次选中任意一个分类的id * 在组件中发送一级分类请求,拿到数据渲染 * select组件需要使用v-model收集选中的option的value属性值,才能真正使用select - day03 - 三级分类的完整功能 * 把select组件的v-model和pinia中的值直接进行数据双向绑定,pinia中可以直接收集我们选中的值 * 给一级绑定change事件,重新发送二级请求;给二级绑定change事件,重新发送三级请求 * 每次一级更新的时候,二级和三级清空,每次二级更新的时候,三级要清空 - 属性列表静态 * card组件+ table组件 * table组件中,给列设置宽度,没有设置宽度的把剩余距离平分 - 平台属性的api及类型 * 在api中新建一个attr.ts 用来书写attr中的api请求 * 封装请求并完成类型书写 - 平台属性的组件内获取数据 * 使用watch监听category3Id的改变,但是要注意他改变为null的情况,为null,则应该清空 * 在组件内定义一个属性列表的变量,当watch中发送请求的时候,把得到的结果赋值给这个变量 * 拿到变量以后进行静态数据渲染 - 平台属性的新增属性静态及切换 * 新增一个添加平台属性的结构 * 把平台属性列表和添加静态两个视图使用条件渲染控制只能展示一个 - 平台属性新增属性逻辑 * 先创建一个newAttr用来收集新创建的属性(newAttr的格式是请求新增的接口文档看到的) * 当点击创建属性值的时候,然后要创建一个新的newAttrValue的对象,收集当前新增的属性值 * 把创建的新的newAttrValue对象插入到newAttr的attrValueList的数组中 * 把表格的数据和newAttr的attrValueList进行绑定 * 一旦attrValueList有新增,则在表格中展示的时候展示一个input,并把这个input的值和attrValueList对应的属性值进行双向绑定,我们就可以新增和收集了 - 修改属性时,回填数据 * 修改属性时,可以通过row拿到当前属性的完整数据 * 把这个数据深拷贝之后,直接赋值给newAttr即可 - 开发模式和编辑模式 * 新增属性的时候,要把newAttr恢复原始数据 * 因为每一条属性值都有开发模式和编辑模式,所以需要给newAttr的每一个属性值对象添加一个isEdit属性 * 如果是新增则默认isEdit为true * 如果是修改则默认给所有的属性值对象 idEdit为false - 查看模式和编辑模式的切换 * 查看模式切换编辑模式的时候,只需要把当前值(row)的isEdit变成true * 编辑模式切换到查看模式的时候,需要把当前值(row)的isEdit变成false + 还要判断当前是否为空,如果为空则删除 + 还要判断其他值有没有和自己相等的,如果有则删除自己 - 编辑模式下自动获取焦点 * 首先编辑模式和查看模式是通过v-if控制的,只可能出现一个input * 通过ref获取到这个input的DOM * 当新增属性值的时候或者切换到编辑模式的时候,自动获取焦点(focus方法) * 需要使用nextTick(当本轮数据更新结束后,并且对应的DOM也更新结束后才会执行内部的回调函数) - 删除某个属性值 * 绑定点击时候,接受到当前数据的index,使用splice直接删除即可 - 提交新增或者修改 * 首先要整理数据 + 去掉数据中的isEdit属性 + 判断属性中值不能是空 * 发送提交请求 * 提交成功之后,切换到列表模式,并且重新发送列表请求 - 删除某个属性的数据 * 首先书写一个删除确认的气泡框 * 书写删除的api * 在事件函数中调用api * 删除成功后,重新发送列表请求 - 按钮的可操作性 * 添加属性按钮只能是拥有category3id的时候才能使用 * 添加属性值按钮只能有属性名的时候才能使用 * 保存按钮只能是有属性名并且有属性值的时候才能使用 * 当进入新增或者修改的时候,三级分类要禁用 - day04 - 搭建spu架子 * 复用Category组件 * 定义三个子组件进行条件渲染,定义一个变量控制渲染条件 - spuList的静态搭建 - 点击spuList中的某些按钮进行组件切换 * 通过自定义事件 向父组件传值 * 父组件根据新的值进行切换 - 搭建spu和sku的api和类型 - 完成spu列表的渲染 * 使用watch监听category3Id的改变 * 使用watch监听页码的切换 * 使用v-loading控制加载中状态 - 点击添加或者修改切换到spuForm * 如果说是修改,则需要把修改的当前行的row直接交给spuForm组件 * 在父组件中,初始化一个spuInfo的信息 * 如果是修改,则把spuInfo设置为row,如果是新增,则spuInfo是初始值 * 我们通过props把spuInfo的值传递给spuForm - spuForm的静态完成 - spuForm的初始化请求数据 * 根据传递进来的spuInfo的值的id 确定当前是新增还是修改 * 判断当前是修改还是新增 来发送其他的数据请求 + 如果是新增则需要发送1. 所有品牌列表 2.所有销售属性列表 + 如果是修改则需要发发送1. 所有品牌列表 2.所有销售属性列表 3.根据当前spuId获取图片列表 4. 根据当前spuId获取销售属性列表 * 再trademark中新增一个api,请求所有的品牌列表 - day05 - 在spuForm中收集品牌id - 处理spuForm中的数据,让图片墙展示 * 图片墙展示的数据和后端给的imgList的数据不一致 * 我们需要给后端的数据扩展url和name属性 * 注意添加ts - 计算属性计算当前spu没有使用过的销售属性列表 - 每次进入spuForm的时候 要清空spuInfo的数据 - 添加销售属性的逻辑 * 先确定在下拉列表中要收集什么东西(收集id和name) * 下拉列表的value就要收集两个值,只能通过字符串拼接的方式收集两个 * 把下拉列表的双向绑定绑定给一个数据 * 当点击添加按钮的时候,拿到双向绑定的数据 进行处理,并给spu自己的销售属性添加一个新值即可 - 收集销售属性值的查看和编辑模式切换 * 给销售属性值一栏添加一个input和button进行条件渲染 * 给所有的自己的销售属性列表的每一个值添加一个isEdit选项(用来控制当前是查看还是编辑) * 给刚才已经写好的新增属性 添加一个isEdit选项 * 给按钮绑定点击事件,切换到编辑模式,并让input获取焦点 * 给input绑定失去焦点事件,切换到按钮模式 - 收集自己的销售属性的销售属性值 * 在input失去焦点的时候进行收集 * 先判断输入的内容是否为空 * 再判断输入的内容是否有重复 * 向当前row的销售属性中的属性值列表添加数据 * 记得清空input输入框的双向绑定的数据 - 删除某个属性值 * 每一个tag上有一个close事件,事件触发的时候传入当前的row和index * 在事件函数中通过splice删除某条数据即可 - 删除某条销售属性 * 删除事件中拿到当前row的index,使用splice删除即可 - 保存新增或者修改spuForm * 整理销售属性数据,取掉isEdit * 整理图片列表数据,把新上传的数据整理一下 * 把销售属性数据和图片列表数据交给spuInfo * 判断是新增还是修改,进行发送请求 - skuForm的静态 - skuForm的初始化数据请求 * 请求平台属性列表 * 请求当前spu的销售属性列表 * 请求当前spu的图片列表 - skuForm数据渲染 * 把刚才请求到的数据进行渲染 * 给spuList的watch添加一个立即监听 * 把skuForm的取消按钮完成 - day06 - 定义一个初始化的数据收集 - 收集简单的属性 - skuInfo的平台属性收集 * 在attr的列表上每一个数据都添加一个selectData属性,用来每一个select进行数据双向绑定收集 * 注意添加ts - skuInfo的销售属性收集 * 在saleAttr的列表上每一个数据都添加一个selectData属性,用来每一个select进行数据双向绑定收集 * 注意添加ts - skuInfo收集图片 * 直接使用table上的selection-change事件的参数就可以收集 - 默认图片的排他和收集 * 给spuImgList的数据添加一个isDefault属性 * 每一个设置默认按钮都还有一个默认按钮的tag标签,进行条件渲染 * 点击默认图片按钮,使用排他 * 把点击的默认图片收集到skuInfo中 - 整理skuInfo的数据并提交 * 整理imgList * 整理平台属性(只需要提交两个id即可) * 整理销售属性(只需要提交两个id即可) * 提交 - 点击查看某个spu的sku列表 * 需要使用dialog组件 * 根据spuid获取skuList * 在表格中展示 - 删除某一个spu - spu中按钮的可操作性 * 没有选择3级分类,不能添加spu * 一旦不再spuList列表,三级分类就要禁用 - sku管理的静态及数据渲染 * 静态 * 请求数据 * 数据渲染 - 上下架的操作 * 条件渲染上下架的按钮 * 上下架点击切换,并重新发送请求 - 删除sku - 页码的实现 - 抽屉的实现 * 抽屉的展示 * 抽屉的内部布局 * 抽屉的数据渲染 - 样式的实现 - 深度选择器的使用