苍穹外卖项目前端DAY03

前端DAY03

1、套餐管理

1.1、套餐分页查询

1.1.1、需求分析和接口设计

产品原型:

业务规则:

  • 根据页码展示套餐信息
  • 每页展示10条数据
  • 分页查询时可以根据需要,输入套餐名称、套餐分类、售卖状态进行查询

接口设计:

  • 套餐分页查询接口

  • 分类查询接口

1.1.2、代码开发
  • 从路由文件router.ts中找到套餐管理页面(组件)

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 制作页面头部效果

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 注意:

    • 输入框、按钮、下拉框都是使用ElementUI提供的组件

    • 对于前端的组件只需要参考ElementUI提供的文档,进行修改即可

  • 导入查询套餐分类的Js方法,动态填充套餐分类下拉框

  • 页面组件和数据模型进行相应调整

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • 为查询按钮绑定事件,发送Ajax请求获取分页数据

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

完整代码

<template>
  <div class="dashboard-container">
    <div class="container">
      <div class="tableBar">
        <label style="margin-right: 5px;">
        套餐名称:
        </label>
        <el-input v-model="name" placeholder="请输入套餐名称" style="width: 15%"/>

        <label style="margin-right: 5px;">
        套餐分类:
        </label>
        <el-select v-model="categoryId" placeholder="请选择">
          <el-option
            v-for="item in options"
            :key="item.id"
            :label="item.name"
            :value="item.id">
          </el-option>
        </el-select>
        <label style="margin-right: 5px;">
        售卖状态:
        </label>
        <el-select v-model="saleStatus" placeholder="请选择">
          <el-option
            v-for="item in saleStatusArr"
            :key="item.value"
            :label="item.label"
            :value="item.value">
          </el-option>
        </el-select>
        
        <el-button type = "primary" style="margin-left: 20px" @click="pageQuery()">查询</el-button>
        <div style="float: right">
          <el-button type="danger">批量删除</el-button>
          <el-button type="info">+ 新建套餐</el-button>
        </div>
      </div>
    </div>
      <el-table :data="records" stripe class="tableBox" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="25" />
        <el-table-column prop="name" label="套餐名称" />
        <el-table-column label="图片">
          <template slot-scope="scope">
            <el-image style="width: 80px; height: 40px; border: none" :src="scope.row.image"></el-image>
          </template>
        </el-table-column>
        <el-table-column prop="categoryName" label="套餐分类" />
        <el-table-column prop="price" label="套餐价"/>
        <el-table-column label="售卖状态">
          <template slot-scope="scope">
            <div class="tableColumn-status" :class="{ 'stop-use': scope.row.status === 0 }">
              {{ scope.row.status === 0 ? '停售' : '启售' }}
            </div>
          </template>
        </el-table-column>
        <el-table-column prop="updateTime" label="最后操作时间" />
        <el-table-column label="操作" align="center" width="250px">
          <template slot-scope="scope">
            <el-button type="text" size="small"> 修改 </el-button>
            <el-button type="text" size="small" @click="handleStartOrStop(scope.row)">
              {{ scope.row.status == '1' ? '停售' : '启售' }}
            </el-button>
            <el-button type="text" size="small" @click="handleDelete('S',scope.row.id)"> 删除 </el-button>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination class="pageList"
                     :page-sizes="[10, 20, 30, 40]"
                     :page-size="pageSize"
                     layout="total, sizes, prev, pager, next, jumper"
                     :total="total"
                     @size-change="handleSizeChange"
                     @current-change="handleCurrentChange" />
    </div>
    </div>
  </div>
</template>

<script lang="ts">
import { getCategoryByType } from "@/api/category";
import { getSetmealPage } from "@/api/setMeal"
export default {
    //模型数据
    data(){
    return {
      name: '', //员工姓名,对应上面的输入框 
      page: 1, //页码
      pageSize: 10, //每页记录数
      total: 0, //总记录数
      records: [], //当前页面要展示的数据集合
      options: [],
        categoryId: '', //分类id
        saleStatusArr:[
          {
            value: '0',
            label: '停售'
          },
          {
            value: '1',
            label: '起售'
          }
        ]
    }
 },
 created() {
  //查询套餐分类,用于填充查询页面的下拉框
  getCategoryByType({type:2})
    .then((res) => {
     if (res.data.code === 1) {
      this.options = res.data.data
     } 
    })
    //页面加载完成后查询套餐数据
    this.pageQuery()
 },
 methods: {
  //分页查询
  pageQuery(){
    //封装分页查询参数
    const params = {
      Page: this.page,
      pageSize: this.pageSize,
      name: this.name,
      status: this.status,
      categoryId: this.categoryId
    }
    getSetmealPage(params).then((res) => {
      if(res.data.code === 1){
        this.total = res.data.data.total
        this.records = res.data.data.records
      }
    }).catch((err) => {
      
    });
  },
  
  handleSizeChange(pageSize){
    this.pageSize = pageSize
    this.pageQuery()
  },
  handleCurrentChange(page){
    this.page = page
    this.pageQuery()
  }
 },
}
</script>
<style lang="scss">
.el-table-column--selection .cell {
  padding-left: 10px;
}
</style>
<style lang="scss" scoped>
.dashboard {
  &-container {
    margin: 30px;

    .container {
      background: #fff;
      position: relative;
      z-index: 1;
      padding: 30px 28px;
      border-radius: 4px;

      .tableBar {
        margin-bottom: 20px;
        .tableLab {
          float: right;
          span {
            cursor: pointer;
            display: inline-block;
            font-size: 14px;
            padding: 0 20px;
            color: $gray-2;
          }
        }
      }

      .tableBox {
        width: 100%;
        border: 1px solid $gray-5;
        border-bottom: 0;
      }

      .pageList {
        text-align: center;
        margin-top: 30px;
      }
      //查询黑色按钮样式
      .normal-btn {
        background: #333333;
        color: white;
        margin-left: 20px;
      }
    }
  }
}
</style>

1.1.3、功能测试

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.2、起售停售套餐

1.2.1、需求分析和接口设计

业务规则:

  • 可以对状态为“启售”的套餐进行“停售”操作
  • 可以对状态为“停售”的套餐进行“启售”操作

接口设计:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.2.2、代码开发

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

完整代码

<template>
  <div class="dashboard-container">
    <div class="container">
      <div class="tableBar">
        <label style="margin-right: 5px;">
        套餐名称:
        </label>
        <el-input v-model="name" placeholder="请输入套餐名称" style="width: 15%"/>

        <label style="margin-right: 5px;">
        套餐分类:
        </label>
        <el-select v-model="categoryId" placeholder="请选择">
          <el-option
            v-for="item in options"
            :key="item.id"
            :label="item.name"
            :value="item.id">
          </el-option>
        </el-select>
        <label style="margin-right: 5px;">
        售卖状态:
        </label>
        <el-select v-model="saleStatus" placeholder="请选择">
          <el-option
            v-for="item in saleStatusArr"
            :key="item.value"
            :label="item.label"
            :value="item.value">
          </el-option>
        </el-select>
        
        <el-button type = "primary" style="margin-left: 20px" @click="pageQuery()">查询</el-button>
        <div style="float: right">
          <el-button type="danger">批量删除</el-button>
          <el-button type="info">+ 新建套餐</el-button>
        </div>
      </div>
    </div>
      <el-table :data="records" stripe class="tableBox" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="25" />
        <el-table-column prop="name" label="套餐名称" />
        <el-table-column label="图片">
          <template slot-scope="scope">
            <el-image style="width: 80px; height: 40px; border: none" :src="scope.row.image"></el-image>
          </template>
        </el-table-column>
        <el-table-column prop="categoryName" label="套餐分类" />
        <el-table-column prop="price" label="套餐价"/>
        <el-table-column label="售卖状态">
          <template slot-scope="scope">
            <div class="tableColumn-status" :class="{ 'stop-use': scope.row.status === 0 }">
              {{ scope.row.status === 0 ? '停售' : '启售' }}
            </div>
          </template>
        </el-table-column>
        <el-table-column prop="updateTime" label="最后操作时间" />
        <el-table-column label="操作" align="center" width="250px">
          <template slot-scope="scope">
            <el-button type="text" size="small"> 修改 </el-button>
            <el-button type="text" size="small" @click="handleStartOrStop(scope.row)">
              {{ scope.row.status == '1' ? '停售' : '启售' }}
            </el-button>
            <el-button type="text" size="small" @click="handleDelete('S',scope.row.id)"> 删除 </el-button>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination class="pageList"
                     :page-sizes="[10, 20, 30, 40]"
                     :page-size="pageSize"
                     layout="total, sizes, prev, pager, next, jumper"
                     :total="total"
                     @size-change="handleSizeChange"
                     @current-change="handleCurrentChange" />
    </div>
    </div>
  </div>
</template>

<script lang="ts">
import { getCategoryByType } from "@/api/category";
import { getSetmealPage,enableOrDisableSetmeal } from "@/api/setMeal"
export default {
    //模型数据
    data(){
    return {
      name: '', //员工姓名,对应上面的输入框 
      page: 1, //页码
      pageSize: 10, //每页记录数
      total: 0, //总记录数
      records: [], //当前页面要展示的数据集合
      options: [],
        categoryId: '', //分类id
        saleStatusArr:[
          {
            value: '0',
            label: '停售'
          },
          {
            value: '1',
            label: '起售'
          }
        ]
    }
 },
 created() {
  //查询套餐分类,用于填充查询页面的下拉框
  getCategoryByType({type:2})
    .then((res) => {
     if (res.data.code === 1) {
      this.options = res.data.data
     } 
    })
    //页面加载完成后查询套餐数据
    this.pageQuery()
 },
 methods: {
  //分页查询
  pageQuery(){
    //封装分页查询参数
    const params = {
      Page: this.page,
      pageSize: this.pageSize,
      name: this.name,
      status: this.status,
      categoryId: this.categoryId
    }
    getSetmealPage(params).then((res) => {
      if(res.data.code === 1){
        this.total = res.data.data.total
        this.records = res.data.data.records
      }
    }).catch((err) => {
      
    });
  },
  handleSizeChange(pageSize){
    this.pageSize = pageSize
    this.pageQuery()
  },
  handleCurrentChange(page){
    this.page = page
    this.pageQuery()
  },
  //套餐起售停售操作
  handleStartOrStop(row){
    const p ={
      id: row.id,
      status: !row.status ? 1:0
    }
    this.$confirm('此操作将会修改套餐的状态,是否继续?','提示',{
      confirmButtonText:'确定',
      cancelButtonText:'取消',
      type:'warning'
    }).then((res) => {
        enableOrDisableSetmeal(p).then(res =>{
        if(res.data.code ===1){
          this.$message.success('套餐售卖状态修改成功')
          this.pageQuery()
        }
      })
    }).catch((err) => {
      
    });

   
  }

 }
}
</script>
<style lang="scss">
.el-table-column--selection .cell {
  padding-left: 10px;
}
</style>
<style lang="scss" scoped>
.dashboard {
  &-container {
    margin: 30px;

    .container {
      background: #fff;
      position: relative;
      z-index: 1;
      padding: 30px 28px;
      border-radius: 4px;

      .tableBar {
        margin-bottom: 20px;
        .tableLab {
          float: right;
          span {
            cursor: pointer;
            display: inline-block;
            font-size: 14px;
            padding: 0 20px;
            color: $gray-2;
          }
        }
      }

      .tableBox {
        width: 100%;
        border: 1px solid $gray-5;
        border-bottom: 0;
      }

      .pageList {
        text-align: center;
        margin-top: 30px;
      }
      //查询黑色按钮样式
      .normal-btn {
        background: #333333;
        color: white;
        margin-left: 20px;
      }
    }
  }
}
</style>

1.2.3、功能测试

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

1.3、删除套餐

1.3.1、需求分析和接口设计

产品原型:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

业务规则:

  • 点击删除按钮,删除指定的一个套餐
  • 勾选需要删除的套餐,点击批量删除按钮,删除选中的一个或多个套餐

接口设计:一个接口,兼容两种删除方式

1.3.2、代码开发
  • 在setMeal.ts中封装删除套餐方法,发送Ajax请求

完整代码

<template>
  <div class="dashboard-container">
    <div class="container">
      <div class="tableBar">
        <label style="margin-right: 5px;">
        套餐名称:
        </label>
        <el-input v-model="name" placeholder="请输入套餐名称" style="width: 15%"/>

        <label style="margin-right: 5px;">
        套餐分类:
        </label>
        <el-select v-model="categoryId" placeholder="请选择">
          <el-option
            v-for="item in options"
            :key="item.id"
            :label="item.name"
            :value="item.id">
          </el-option>
        </el-select>
        <label style="margin-right: 5px;">
        售卖状态:
        </label>
        <el-select v-model="saleStatus" placeholder="请选择">
          <el-option
            v-for="item in saleStatusArr"
            :key="item.value"
            :label="item.label"
            :value="item.value">
          </el-option>
        </el-select>
        
        <el-button type = "primary" style="margin-left: 20px" @click="pageQuery()">查询</el-button>
        <div style="float: right">
          <el-button type="danger" @click="handleDelete('B')">批量删除</el-button>
          <el-button type="info">+ 新建套餐</el-button>
        </div>
      </div>
    </div>
      <el-table :data="records" stripe class="tableBox" @selection-change="handleSelectionChange">
        <el-table-column type="selection" width="25" />
        <el-table-column prop="name" label="套餐名称" />
        <el-table-column label="图片">
          <template slot-scope="scope">
            <el-image style="width: 80px; height: 40px; border: none" :src="scope.row.image"></el-image>
          </template>
        </el-table-column>
        <el-table-column prop="categoryName" label="套餐分类" />
        <el-table-column prop="price" label="套餐价"/>
        <el-table-column label="售卖状态">
          <template slot-scope="scope">
            <div class="tableColumn-status" :class="{ 'stop-use': scope.row.status === 0 }">
              {{ scope.row.status === 0 ? '停售' : '启售' }}
            </div>
          </template>
        </el-table-column>
        <el-table-column prop="updateTime" label="最后操作时间" />
        <el-table-column label="操作" align="center" width="250px">
          <template slot-scope="scope">
            <el-button type="text" size="small"> 修改 </el-button>
            <el-button type="text" size="small" @click="handleStartOrStop(scope.row)">
              {{ scope.row.status == '1' ? '停售' : '启售' }}
            </el-button>
            <el-button type="text" size="small" @click="handleDelete('S',scope.row.id)"> 删除 </el-button>
          </template>
        </el-table-column>
      </el-table>
      <el-pagination class="pageList"
                     :page-sizes="[10, 20, 30, 40]"
                     :page-size="pageSize"
                     layout="total, sizes, prev, pager, next, jumper"
                     :total="total"
                     @size-change="handleSizeChange"
                     @current-change="handleCurrentChange" />
    </div>
</template>

<script lang="ts">
import { getCategoryByType } from "@/api/category";
import { getSetmealPage,enableOrDisableSetmeal,deleteSetmeal } from "@/api/setMeal"
export default {
    //模型数据
    data(){
    return {
      name: '', //员工姓名,对应上面的输入框 
      page: 1, //页码
      pageSize: 10, //每页记录数
      total: 0, //总记录数
      records: [], //当前页面要展示的数据集合
      options: [],
        categoryId: '', //分类id
        saleStatusArr:[
          {
            value: '0',
            label: '停售'
          },
          {
            value: '1',
            label: '起售'
          }
        ],
        status:'', //售卖状态
        multipleSelection: '' //当前表格选中的多个元素
    }
 },
 created() {
  //查询套餐分类,用于填充查询页面的下拉框
  getCategoryByType({type:2})
    .then((res) => {
     if (res.data.code === 1) {
      this.options = res.data.data
     } 
    })
    //页面加载完成后查询套餐数据
    this.pageQuery()
 },
 methods: {
  //分页查询
  pageQuery(){
    //封装分页查询参数
    const params = {
      Page: this.page,
      pageSize: this.pageSize,
      name: this.name,
      status: this.status,
      categoryId: this.categoryId
    }
    getSetmealPage(params).then((res) => {
      if(res.data.code === 1){
        this.total = res.data.data.total
        this.records = res.data.data.records
      }
    }).catch((err) => {
      
    });
  },
  handleSizeChange(pageSize){
    this.pageSize = pageSize
    this.pageQuery()
  },
  handleCurrentChange(page){
    this.page = page
    this.pageQuery()
  },
  //套餐起售停售操作
  handleStartOrStop(row){
    const p ={
      id: row.id,
      status: !row.status ? 1:0
    }
    this.$confirm('此操作将会修改套餐的状态,是否继续?','提示',{
      confirmButtonText:'确定',
      cancelButtonText:'取消',
      type:'warning'
    }).then((res) => {
        enableOrDisableSetmeal(p).then(res =>{
        if(res.data.code ===1){
          this.$message.success('套餐售卖状态修改成功')
          this.pageQuery()
        }
      })
    }).catch((err) => {
      
    });

   
  },
  //删除套餐
  handleDelete(type: string,id: string){

    this.$confirm('确定删除当前指定的套餐,是否继续?','提示',{
      confirmButtonText:'确定',
      cancelButtonText:'取消',
      type:'warning'
    }).then(() => {
      let param = ''
      if(type == 'B'){ //批量删除
        const arr = new Array
        this.multipleSelection.forEach(element => {
          arr.push(element.id)
        })
        param = arr.join(',')
      }else{ //单一删除
        param = id
      }

      deleteSetmeal(id).then(res =>{
        if(res.data.code ===1){
          this.$message.success('删除成功')
          this.pageQuery()
        }else{
          this.$message.error(res.data.msg)
       }
        })
      })


  },
  //复选框
  handleSelectionChange(val){
    this.multipleSelection = val
  }


 }
}
</script>
<style lang="scss">
.el-table-column--selection .cell {
  padding-left: 10px;
}
</style>
<style lang="scss" scoped>
.dashboard {
  &-container {
    margin: 30px;

    .container {
      background: #fff;
      position: relative;
      z-index: 1;
      padding: 30px 28px;
      border-radius: 4px;

      .tableBar {
        margin-bottom: 20px;
        .tableLab {
          float: right;
          span {
            cursor: pointer;
            display: inline-block;
            font-size: 14px;
            padding: 0 20px;
            color: $gray-2;
          }
        }
      }

      .tableBox {
        width: 100%;
        border: 1px solid $gray-5;
        border-bottom: 0;
      }

      .pageList {
        text-align: center;
        margin-top: 30px;
      }
      //查询黑色按钮样式
      .normal-btn {
        background: #333333;
        color: white;
        margin-left: 20px;
      }
    }
  }
}
</style>

ve;
z-index: 1;
padding: 30px 28px;
border-radius: 4px;

  .tableBar {
    margin-bottom: 20px;
    .tableLab {
      float: right;
      span {
        cursor: pointer;
        display: inline-block;
        font-size: 14px;
        padding: 0 20px;
        color: $gray-2;
      }
    }
  }

  .tableBox {
    width: 100%;
    border: 1px solid $gray-5;
    border-bottom: 0;
  }

  .pageList {
    text-align: center;
    margin-top: 30px;
  }
  //查询黑色按钮样式
  .normal-btn {
    background: #333333;
    color: white;
    margin-left: 20px;
  }
}

}
}


#### 1.3.3、功能测试

![\[外链图片转存中...(img-RjvVBZgA-1725427732990)\]](https://i-blog.csdnimg.cn/direct/b1ea397e7a7e4c21ae4d8ea308f08f45.png)


![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://i-blog.csdnimg.cn/direct/73025364626949a3910ce268a97ccbbf.png)


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值