国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

vue項(xiàng)目實(shí)戰(zhàn)-電商后臺(tái)管理系統(tǒng)

這篇具有很好參考價(jià)值的文章主要介紹了vue項(xiàng)目實(shí)戰(zhàn)-電商后臺(tái)管理系統(tǒng)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

項(xiàng)目簡(jiǎn)介:

該項(xiàng)目為電商后臺(tái)的管理系統(tǒng)。設(shè)計(jì)了登錄頁(yè)面。

vue電商后臺(tái)管理系統(tǒng),前端學(xué)習(xí),項(xiàng)目實(shí)戰(zhàn)案例以及bug處理,前端,1024程序員節(jié)

管理人員需要通過(guò)輸入正確的用戶(hù)名和密碼才能登錄。登陸成功之后進(jìn)入管理頁(yè)面:

vue電商后臺(tái)管理系統(tǒng),前端學(xué)習(xí),項(xiàng)目實(shí)戰(zhàn)案例以及bug處理,前端,1024程序員節(jié)

管理頁(yè)面由五個(gè)子模塊組成:用戶(hù)管理,權(quán)限管理,商品管理,訂單管理,數(shù)據(jù)統(tǒng)計(jì);

每個(gè)子模塊有若干子模塊組成,用戶(hù)管理下->用戶(hù)列表,權(quán)限管理->角色列表,權(quán)限管理,商品管理->商品列表,分類(lèi)參數(shù),商品分配,訂單管理->訂單列表,數(shù)據(jù)統(tǒng)計(jì)->數(shù)據(jù)報(bào)表

登錄頁(yè)面

登錄頁(yè)面中對(duì)用戶(hù)輸入的內(nèi)容進(jìn)行預(yù)校驗(yàn),如果不符合要求則,則不向后端發(fā)送請(qǐng)求,同事掛載路由守衛(wèi),防止強(qiáng)制跳轉(zhuǎn)。同時(shí)設(shè)置令牌校驗(yàn),避免重復(fù)登錄。如果用戶(hù)輸入格式正確的用戶(hù)名以及密碼時(shí),向后端發(fā)送請(qǐng)求,請(qǐng)求通過(guò)則跳轉(zhuǎn)到管理頁(yè)面,否則返回登錄頁(yè)面。

路由導(dǎo)航守衛(wèi):

// 掛載路由導(dǎo)航守衛(wèi)
router.beforeEach((to, from, next) => {
  // to 將要訪(fǎng)問(wèn)的路徑
  // from 代表從哪個(gè)路徑跳轉(zhuǎn)而來(lái)
  // next 是一個(gè)函數(shù),表示放行
  //     next()  放行    next('/login')  強(qiáng)制跳轉(zhuǎn)

  if (to.path === '/login') return next()
  // 獲取token
  const tokenStr = window.sessionStorage.getItem('token')
  if (!tokenStr) return next('/login')
  next()
})

登錄頁(yè)面核心代碼:

<template>
  <div class="login_container">
    <div class="login_box">
      <!-- 頭像區(qū)域 -->
      <div class="avatar_box">
        <img src="../assets/logo.png" alt="">
      </div>
      <!-- 登錄表單區(qū)域 -->
      <el-form ref="loginFormRef" :model="loginForm" :rules="loginFormRules" label-width="0px" class="login_form">
        <!-- 用戶(hù)名 -->
        <el-form-item prop="username">
          <el-input v-model="loginForm.username" prefix-icon="iconfont icon-user"></el-input>
        </el-form-item>
        <!-- 密碼 -->
        <el-form-item prop="password">
          <el-input v-model="loginForm.password" prefix-icon="iconfont icon-3702mima" type="password"></el-input>
        </el-form-item>
        <!-- 按鈕區(qū)域 -->
        <el-form-item class="btns">
          <el-button type="primary" @click="login">登錄</el-button>
          <el-button type="info" @click="resetLoginForm">重置</el-button>
        </el-form-item>
      </el-form>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      // 這是登錄表單的數(shù)據(jù)綁定對(duì)象
      loginForm: {
        username: 'admin',
        password: '123456'
      },
      // 這是表單的驗(yàn)證規(guī)則對(duì)象
      loginFormRules: {
        // 驗(yàn)證用戶(hù)名是否合法
        username: [
          { required: true, message: '請(qǐng)輸入登錄名稱(chēng)', trigger: 'blur' },
          { min: 3, max: 10, message: '長(zhǎng)度在 3 到 10 個(gè)字符', trigger: 'blur' }
        ],
        // 驗(yàn)證密碼是否合法
        password: [
          { required: true, message: '請(qǐng)輸入登錄密碼', trigger: 'blur' },
          { min: 6, max: 15, message: '長(zhǎng)度在 6 到 15 個(gè)字符', trigger: 'blur' }
        ]
      }
    }
  },
  methods: {
    // 點(diǎn)擊重置按鈕,重置登錄表單
    resetLoginForm() {
      // console.log(this);
      this.$refs.loginFormRef.resetFields()
    },
    login() {
      this.$refs.loginFormRef.validate(async valid => {
        if (!valid) return
        const { data: res } = await this.$http.post('login', this.loginForm)
        if (res.meta.status !== 200) return this.$message.error('登錄失?。?)
        this.$message.success('登錄成功')
        // 1. 將登錄成功之后的 token,保存到客戶(hù)端的 sessionStorage 中
        //   1.1 項(xiàng)目中出了登錄之外的其他API接口,必須在登錄之后才能訪(fǎng)問(wèn)
        //   1.2 token 只應(yīng)在當(dāng)前網(wǎng)站打開(kāi)期間生效,所以將 token 保存在 sessionStorage 中
        window.sessionStorage.setItem('token', res.data.token)
        // 2. 通過(guò)編程式導(dǎo)航跳轉(zhuǎn)到后臺(tái)主頁(yè),路由地址是 /home
        this.$router.push('/home')
      })
    }
  }
}
</script>

<style lang="less" scoped>
.login_container {
  background-color: #2b4b6b;
  height: 100%;
}

.login_box {
  width: 450px;
  height: 300px;
  background-color: #fff;
  border-radius: 3px;
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%);

  .avatar_box {
    height: 130px;
    width: 130px;
    border: 1px solid #eee;
    border-radius: 50%;
    padding: 10px;
    box-shadow: 0 0 10px #ddd;
    position: absolute;
    left: 50%;
    transform: translate(-50%, -50%);
    background-color: #fff;
    img {
      width: 100%;
      height: 100%;
      border-radius: 50%;
      background-color: #eee;
    }
  }
}

.login_form {
  position: absolute;
  bottom: 0;
  width: 100%;
  padding: 0 20px;
  box-sizing: border-box;
}

.btns {
  display: flex;
  justify-content: flex-end;
}
</style>

菜單實(shí)現(xiàn)

管理頁(yè)面有一個(gè)側(cè)面的兩級(jí)菜單,菜單的數(shù)據(jù)來(lái)自于后端,點(diǎn)擊二級(jí)菜單會(huì)跳轉(zhuǎn)到相應(yīng)的子頁(yè)面中。在el-menu中設(shè)置router屬性,即可通過(guò)index添加到路由上進(jìn)行跳轉(zhuǎn)。

<template>
  <el-container class="home-container">
    <!-- 頭部區(qū)域 -->
    <el-header>
      <div>
        <img src="../assets/heima.png" alt="">
        <span>電商后臺(tái)管理系統(tǒng)</span>
      </div>
      <el-button type="info" @click="logout">退出</el-button>
    </el-header>
    <!-- 頁(yè)面主體區(qū)域 -->
    <el-container>
      <!-- 側(cè)邊欄 -->
      <el-aside :width="isCollapse ? '64px' : '200px'">
        <div class="toggle-button" @click="toggleCollapse">|||</div>
        <!-- 側(cè)邊欄菜單區(qū)域 -->
        <el-menu background-color="#333744" text-color="#fff" active-text-color="#409EFF" unique-opened :collapse="isCollapse" :collapse-transition="false" router :default-active="activePath">
          <!-- 一級(jí)菜單 -->
          <el-submenu :index="item.id + ''" v-for="item in menulist" :key="item.id">
            <!-- 一級(jí)菜單的模板區(qū)域 -->
            <template slot="title">
              <!-- 圖標(biāo) -->
              <i :class="iconsObj[item.id]"></i>
              <!-- 文本 -->
              <span>{{item.authName}}</span>
            </template>

            <!-- 二級(jí)菜單 -->
            <el-menu-item :index="'/' + subItem.path" v-for="subItem in item.children" 
            :key="subItem.id" @click="saveNavState('/' + subItem.path)">
              <template slot="title">
                <!-- 圖標(biāo) -->
                <i class="el-icon-menu"></i>
                <!-- 文本 -->
                <span>{{subItem.authName}}</span>
              </template>
            </el-menu-item>
          </el-submenu>
        </el-menu>
      </el-aside>
      <!-- 右側(cè)內(nèi)容主體 -->
      <el-main>
        <!-- 路由占位符 -->
        <router-view></router-view>
      </el-main>
    </el-container>
  </el-container>
</template>

<script>
export default {
  data() {
    return {
      // 左側(cè)菜單數(shù)據(jù)
      menulist: [],
      iconsObj: {
        '125': 'iconfont icon-user',
        '103': 'iconfont icon-tijikongjian',
        '101': 'iconfont icon-shangpin',
        '102': 'iconfont icon-danju',
        '145': 'iconfont icon-baobiao'
      },
      // 是否折疊
      isCollapse: false,
      // 被激活的鏈接地址
      activePath: ''
    }
  },
  created() {
    this.getMenuList()
    this.activePath = window.sessionStorage.getItem('activePath')
  },
  methods: {
    logout() {
      window.sessionStorage.clear()
      this.$router.push('/login')
    },
    // 獲取所有的菜單
    async getMenuList() {
      const { data: res } = await this.$http.get('menus')
      if (res.meta.status !== 200) return this.$message.error(res.meta.msg)
      this.menulist = res.data
      console.log(res)
    },
    // 點(diǎn)擊按鈕,切換菜單的折疊與展開(kāi)
    toggleCollapse() {
      this.isCollapse = !this.isCollapse
    },
    // 保存鏈接的激活狀態(tài)
    saveNavState(activePath) {
      window.sessionStorage.setItem('activePath', activePath)
      this.activePath = activePath
    }
  }
}
</script>

<style lang="less" scoped>
.home-container {
  height: 100%;
}
.el-header {
  background-color: #373d41;
  display: flex;
  justify-content: space-between;
  padding-left: 0;
  align-items: center;
  color: #fff;
  font-size: 20px;
  > div {
    display: flex;
    align-items: center;
    span {
      margin-left: 15px;
    }
  }
}

.el-aside {
  background-color: #333744;
  .el-menu {
    border-right: none;
  }
}

.el-main {
  background-color: #eaedf1;
}

.iconfont {
  margin-right: 10px;
}

.toggle-button {
  background-color: #4a5064;
  font-size: 10px;
  line-height: 24px;
  color: #fff;
  text-align: center;
  letter-spacing: 0.2em;
  cursor: pointer;
}
</style>

用戶(hù)管理

用戶(hù)列表

用戶(hù)管理下有用戶(hù)列表,這里渲染了后端的用戶(hù)列表,可以編輯用戶(hù)信息,刪除用戶(hù),為用戶(hù)分配角色,還可以對(duì)用戶(hù)是否禁用進(jìn)行管理;除此之外,還添加了查詢(xún)用戶(hù),添加用戶(hù),和分頁(yè)功能。

vue電商后臺(tái)管理系統(tǒng),前端學(xué)習(xí),項(xiàng)目實(shí)戰(zhàn)案例以及bug處理,前端,1024程序員節(jié)

核心代碼:

<template>
  <div>
    <!-- 面包屑導(dǎo)航區(qū)域 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">首頁(yè)</el-breadcrumb-item>
      <el-breadcrumb-item>用戶(hù)管理</el-breadcrumb-item>
      <el-breadcrumb-item>用戶(hù)列表</el-breadcrumb-item>
    </el-breadcrumb>

    <!-- 卡片視圖區(qū)域 -->
    <el-card>
      <!-- 搜索與添加區(qū)域 -->
      <el-row :gutter="20">
        <el-col :span="8">
          <el-input placeholder="請(qǐng)輸入內(nèi)容" v-model="queryInfo.query" clearable @clear="getUserList">
            <el-button slot="append" icon="el-icon-search" @click="getUserList"></el-button>
          </el-input>
        </el-col>
        <el-col :span="4">
          <el-button type="primary" @click="addDialogVisible = true">添加用戶(hù)</el-button>
        </el-col>
      </el-row>

      <!-- 用戶(hù)列表區(qū)域 -->
      <el-table :data="userlist" border stripe>
        <el-table-column type="index"></el-table-column>
        <el-table-column label="姓名" prop="username"></el-table-column>
        <el-table-column label="郵箱" prop="email"></el-table-column>
        <el-table-column label="電話(huà)" prop="mobile"></el-table-column>
        <el-table-column label="角色" prop="role_name"></el-table-column>
        <el-table-column label="狀態(tài)">
          <template slot-scope="scope">
            <el-switch v-model="scope.row.mg_state" @change="userStateChanged(scope.row)">
            </el-switch>
          </template>
        </el-table-column>
        <el-table-column label="操作" width="180px">
          <template slot-scope="scope">
            <!-- 修改按鈕 -->
            <el-button type="primary" icon="el-icon-edit" size="mini" @click="showEditDialog(scope.row.id)"></el-button>
            <!-- 刪除按鈕 -->
            <el-button type="danger" icon="el-icon-delete" size="mini" @click="removeUserById(scope.row.id)"></el-button>
            <!-- 分配角色按鈕 -->
            <el-tooltip effect="dark" content="分配角色" placement="top" :enterable="false">
              <el-button type="warning" icon="el-icon-setting" size="mini" @click="setRole(scope.row)"></el-button>
            </el-tooltip>
          </template>
        </el-table-column>
      </el-table>

      <!-- 分頁(yè)區(qū)域 -->
      <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="queryInfo.pagenum" :page-sizes="[1, 2, 5, 10]" :page-size="queryInfo.pagesize" layout="total, sizes, prev, pager, next, jumper" :total="total">
      </el-pagination>
    </el-card>

    <!-- 添加用戶(hù)的對(duì)話(huà)框 -->
    <el-dialog title="添加用戶(hù)" :visible.sync="addDialogVisible" width="50%" @close="addDialogClosed">
      <!-- 內(nèi)容主體區(qū)域 -->
      <el-form :model="addForm" :rules="addFormRules" ref="addFormRef" label-width="70px">
        <el-form-item label="用戶(hù)名" prop="username">
          <el-input v-model="addForm.username"></el-input>
        </el-form-item>
        <el-form-item label="密碼" prop="password">
          <el-input v-model="addForm.password"></el-input>
        </el-form-item>
        <el-form-item label="郵箱" prop="email">
          <el-input v-model="addForm.email"></el-input>
        </el-form-item>
        <el-form-item label="手機(jī)" prop="mobile">
          <el-input v-model="addForm.mobile"></el-input>
        </el-form-item>
      </el-form>
      <!-- 底部區(qū)域 -->
      <span slot="footer" class="dialog-footer">
        <el-button @click="addDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="addUser">確 定</el-button>
      </span>
    </el-dialog>

    <!-- 修改用戶(hù)的對(duì)話(huà)框 -->
    <el-dialog title="修改用戶(hù)" :visible.sync="editDialogVisible" width="50%" @close="editDialogClosed">
      <el-form :model="editForm" :rules="editFormRules" ref="editFormRef" label-width="70px">
        <el-form-item label="用戶(hù)名">
          <el-input v-model="editForm.username" disabled></el-input>
        </el-form-item>
        <el-form-item label="郵箱" prop="email">
          <el-input v-model="editForm.email"></el-input>
        </el-form-item>
        <el-form-item label="手機(jī)" prop="mobile">
          <el-input v-model="editForm.mobile"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="editDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="editUserInfo">確 定</el-button>
      </span>
    </el-dialog>

    <!-- 分配角色的對(duì)話(huà)框 -->
    <el-dialog title="分配角色" :visible.sync="setRoleDialogVisible" width="50%" @close="setRoleDialogClosed">
      <div>
        <p>當(dāng)前的用戶(hù):{{userInfo.username}}</p>
        <p>當(dāng)前的角色:{{userInfo.role_name}}</p>
        <p>分配新角色:
          <el-select v-model="selectedRoleId" placeholder="請(qǐng)選擇">
            <el-option v-for="item in rolesList" :key="item.id" :label="item.roleName" :value="item.id">
            </el-option>
          </el-select>
        </p>
      </div>
      <span slot="footer" class="dialog-footer">
        <el-button @click="setRoleDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="saveRoleInfo">確 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    // 驗(yàn)證郵箱的規(guī)則
    var checkEmail = (rule, value, cb) => {
      // 驗(yàn)證郵箱的正則表達(dá)式
      const regEmail = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+(\.[a-zA-Z0-9_-])+/

      if (regEmail.test(value)) {
        // 合法的郵箱
        return cb()
      }

      cb(new Error('請(qǐng)輸入合法的郵箱'))
    }

    // 驗(yàn)證手機(jī)號(hào)的規(guī)則
    var checkMobile = (rule, value, cb) => {
      // 驗(yàn)證手機(jī)號(hào)的正則表達(dá)式
      const regMobile = /^(0|86|17951)?(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$/

      if (regMobile.test(value)) {
        return cb()
      }

      cb(new Error('請(qǐng)輸入合法的手機(jī)號(hào)'))
    }

    return {
      // 獲取用戶(hù)列表的參數(shù)對(duì)象
      queryInfo: {
        query: '',
        // 當(dāng)前的頁(yè)數(shù)
        pagenum: 1,
        // 當(dāng)前每頁(yè)顯示多少條數(shù)據(jù)
        pagesize: 2
      },
      userlist: [],
      total: 0,
      // 控制添加用戶(hù)對(duì)話(huà)框的顯示與隱藏
      addDialogVisible: false,
      // 添加用戶(hù)的表單數(shù)據(jù)
      addForm: {
        username: '',
        password: '',
        email: '',
        mobile: ''
      },
      // 添加表單的驗(yàn)證規(guī)則對(duì)象
      addFormRules: {
        username: [
          { required: true, message: '請(qǐng)輸入用戶(hù)名', trigger: 'blur' },
          {
            min: 3,
            max: 10,
            message: '用戶(hù)名的長(zhǎng)度在3~10個(gè)字符之間',
            trigger: 'blur'
          }
        ],
        password: [
          { required: true, message: '請(qǐng)輸入密碼', trigger: 'blur' },
          {
            min: 6,
            max: 15,
            message: '用戶(hù)名的長(zhǎng)度在6~15個(gè)字符之間',
            trigger: 'blur'
          }
        ],
        email: [
          { required: true, message: '請(qǐng)輸入郵箱', trigger: 'blur' },
          { validator: checkEmail, trigger: 'blur' }
        ],
        mobile: [
          { required: true, message: '請(qǐng)輸入手機(jī)號(hào)', trigger: 'blur' },
          { validator: checkMobile, trigger: 'blur' }
        ]
      },
      // 控制修改用戶(hù)對(duì)話(huà)框的顯示與隱藏
      editDialogVisible: false,
      // 查詢(xún)到的用戶(hù)信息對(duì)象
      editForm: {},
      // 修改表單的驗(yàn)證規(guī)則對(duì)象
      editFormRules: {
        email: [
          { required: true, message: '請(qǐng)輸入用戶(hù)郵箱', trigger: 'blur' },
          { validator: checkEmail, trigger: 'blur' }
        ],
        mobile: [
          { required: true, message: '請(qǐng)輸入用戶(hù)手機(jī)', trigger: 'blur' },
          { validator: checkMobile, trigger: 'blur' }
        ]
      },
      // 控制分配角色對(duì)話(huà)框的顯示與隱藏
      setRoleDialogVisible: false,
      // 需要被分配角色的用戶(hù)信息
      userInfo: {},
      // 所有角色的數(shù)據(jù)列表
      rolesList: [],
      // 已選中的角色I(xiàn)d值
      selectedRoleId: ''
    }
  },
  created() {
    this.getUserList()
  },
  methods: {
    async getUserList() {
      const { data: res } = await this.$http.get('users', {
        params: this.queryInfo
      })
      if (res.meta.status !== 200) {
        return this.$message.error('獲取用戶(hù)列表失敗!')
      }
      this.userlist = res.data.users
      this.total = res.data.total
      console.log(res)
    },
    // 監(jiān)聽(tīng) pagesize 改變的事件
    handleSizeChange(newSize) {
      // console.log(newSize)
      this.queryInfo.pagesize = newSize
      this.getUserList()
    },
    // 監(jiān)聽(tīng) 頁(yè)碼值 改變的事件
    handleCurrentChange(newPage) {
      console.log(newPage)
      this.queryInfo.pagenum = newPage
      this.getUserList()
    },
    // 監(jiān)聽(tīng) switch 開(kāi)關(guān)狀態(tài)的改變
    async userStateChanged(userinfo) {
      console.log(userinfo)
      const { data: res } = await this.$http.put(
        `users/${userinfo.id}/state/${userinfo.mg_state}`
      )
      if (res.meta.status !== 200) {
        userinfo.mg_state = !userinfo.mg_state
        return this.$message.error('更新用戶(hù)狀態(tài)失??!')
      }
      this.$message.success('更新用戶(hù)狀態(tài)成功!')
    },
    // 監(jiān)聽(tīng)添加用戶(hù)對(duì)話(huà)框的關(guān)閉事件
    addDialogClosed() {
      this.$refs.addFormRef.resetFields()
    },
    // 點(diǎn)擊按鈕,添加新用戶(hù)
    addUser() {
      this.$refs.addFormRef.validate(async valid => {
        if (!valid) return
        // 可以發(fā)起添加用戶(hù)的網(wǎng)絡(luò)請(qǐng)求
        const { data: res } = await this.$http.post('users', this.addForm)

        if (res.meta.status !== 201) {
          this.$message.error('添加用戶(hù)失敗!')
        }

        this.$message.success('添加用戶(hù)成功!')
        // 隱藏添加用戶(hù)的對(duì)話(huà)框
        this.addDialogVisible = false
        // 重新獲取用戶(hù)列表數(shù)據(jù)
        this.getUserList()
      })
    },
    // 展示編輯用戶(hù)的對(duì)話(huà)框
    async showEditDialog(id) {
      // console.log(id)
      const { data: res } = await this.$http.get('users/' + id)

      if (res.meta.status !== 200) {
        return this.$message.error('查詢(xún)用戶(hù)信息失敗!')
      }

      this.editForm = res.data
      this.editDialogVisible = true
    },
    // 監(jiān)聽(tīng)修改用戶(hù)對(duì)話(huà)框的關(guān)閉事件
    editDialogClosed() {
      this.$refs.editFormRef.resetFields()
    },
    // 修改用戶(hù)信息并提交
    editUserInfo() {
      this.$refs.editFormRef.validate(async valid => {
        if (!valid) return
        // 發(fā)起修改用戶(hù)信息的數(shù)據(jù)請(qǐng)求
        const { data: res } = await this.$http.put(
          'users/' + this.editForm.id,
          {
            email: this.editForm.email,
            mobile: this.editForm.mobile
          }
        )

        if (res.meta.status !== 200) {
          return this.$message.error('更新用戶(hù)信息失敗!')
        }

        // 關(guān)閉對(duì)話(huà)框
        this.editDialogVisible = false
        // 刷新數(shù)據(jù)列表
        this.getUserList()
        // 提示修改成功
        this.$message.success('更新用戶(hù)信息成功!')
      })
    },
    // 根據(jù)Id刪除對(duì)應(yīng)的用戶(hù)信息
    async removeUserById(id) {
      // 彈框詢(xún)問(wèn)用戶(hù)是否刪除數(shù)據(jù)
      const confirmResult = await this.$confirm(
        '此操作將永久刪除該用戶(hù), 是否繼續(xù)?',
        '提示',
        {
          confirmButtonText: '確定',
          cancelButtonText: '取消',
          type: 'warning'
        }
      ).catch(err => err)

      // 如果用戶(hù)確認(rèn)刪除,則返回值為字符串 confirm
      // 如果用戶(hù)取消了刪除,則返回值為字符串 cancel
      // console.log(confirmResult)
      if (confirmResult !== 'confirm') {
        return this.$message.info('已取消刪除')
      }

      const { data: res } = await this.$http.delete('users/' + id)

      if (res.meta.status !== 200) {
        return this.$message.error('刪除用戶(hù)失??!')
      }

      this.$message.success('刪除用戶(hù)成功!')
      this.getUserList()
    },
    // 展示分配角色的對(duì)話(huà)框
    async setRole(userInfo) {
      this.userInfo = userInfo

      // 在展示對(duì)話(huà)框之前,獲取所有角色的列表
      const { data: res } = await this.$http.get('roles')
      if (res.meta.status !== 200) {
        return this.$message.error('獲取角色列表失?。?)
      }

      this.rolesList = res.data

      this.setRoleDialogVisible = true
    },
    // 點(diǎn)擊按鈕,分配角色
    async saveRoleInfo() {
      if (!this.selectedRoleId) {
        return this.$message.error('請(qǐng)選擇要分配的角色!')
      }

      const { data: res } = await this.$http.put(
        `users/${this.userInfo.id}/role`,
        {
          rid: this.selectedRoleId
        }
      )

      if (res.meta.status !== 200) {
        return this.$message.error('更新角色失??!')
      }

      this.$message.success('更新角色成功!')
      this.getUserList()
      this.setRoleDialogVisible = false
    },
    // 監(jiān)聽(tīng)分配角色對(duì)話(huà)框的關(guān)閉事件
    setRoleDialogClosed() {
      this.selectedRoleId = ''
      this.userInfo = {}
    }
  }
}
</script>

<style lang="less" scoped>
</style>

權(quán)限管理

角色列表

角色列表中可以創(chuàng)建新的角色,創(chuàng)建的新的角色可以在用戶(hù)管理中賦予用戶(hù),同時(shí)可以為已有的角色賦予權(quán)限

<template>
  <div>
    <!-- 面包屑導(dǎo)航區(qū)域 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">首頁(yè)</el-breadcrumb-item>
      <el-breadcrumb-item>權(quán)限管理</el-breadcrumb-item>
      <el-breadcrumb-item>角色列表</el-breadcrumb-item>
    </el-breadcrumb>

    <!-- 卡片視圖 -->
    <el-card>
      <!-- 添加角色按鈕區(qū)域 -->
      <el-row>
        <el-col>
          <el-button type="primary">添加角色</el-button>
        </el-col>
      </el-row>

      <!-- 角色列表區(qū)域 -->
      <el-table :data="rolelist" border stripe>
        <!-- 展開(kāi)列 -->
        <el-table-column type="expand">
          <template slot-scope="scope">
            <el-row :class="['bdbottom', i1 === 0 ? 'bdtop' : '', 'vcenter']" v-for="(item1, i1) in scope.row.children" :key="item1.id">
              <!-- 渲染一級(jí)權(quán)限 -->
              <el-col :span="5">
                <el-tag closable @close="removeRightById(scope.row, item1.id)">{{item1.authName}}</el-tag>
                <i class="el-icon-caret-right"></i>
              </el-col>
              <!-- 渲染二級(jí)和三級(jí)權(quán)限 -->
              <el-col :span="19">
                <!-- 通過(guò) for 循環(huán) 嵌套渲染二級(jí)權(quán)限 -->
                <el-row :class="[i2 === 0 ? '' : 'bdtop', 'vcenter']" v-for="(item2, i2) in item1.children" :key="item2.id">
                  <el-col :span="6">
                    <el-tag type="success" closable @close="removeRightById(scope.row, item2.id)">{{item2.authName}}</el-tag>
                    <i class="el-icon-caret-right"></i>
                  </el-col>
                  <el-col :span="18">
                    <el-tag type="warning" v-for="item3 in item2.children" :key="item3.id" closable @close="removeRightById(scope.row, item3.id)">{{item3.authName}}</el-tag>
                  </el-col>
                </el-row>
              </el-col>
            </el-row>

            <!-- <pre>
              {{scope.row}}
            </pre> -->
          </template>
        </el-table-column>
        <!-- 索引列 -->
        <el-table-column type="index"></el-table-column>
        <el-table-column label="角色名稱(chēng)" prop="roleName"></el-table-column>
        <el-table-column label="角色描述" prop="roleDesc"></el-table-column>
        <el-table-column label="操作" width="300px">
          <template slot-scope="scope">
            <el-button size="mini" type="primary" icon="el-icon-edit">編輯</el-button>
            <el-button size="mini" type="danger" icon="el-icon-delete">刪除</el-button>
            <el-button size="mini" type="warning" icon="el-icon-setting" @click="showSetRightDialog(scope.row)">分配權(quán)限</el-button>
          </template>
        </el-table-column>
      </el-table>
    </el-card>

    <!-- 分配權(quán)限的對(duì)話(huà)框 -->
    <el-dialog title="分配權(quán)限" :visible.sync="setRightDialogVisible" width="50%" @close="setRightDialogClosed">
      <!-- 樹(shù)形控件 -->
      <el-tree :data="rightslist" :props="treeProps" show-checkbox node-key="id" default-expand-all :default-checked-keys="defKeys" ref="treeRef"></el-tree>
      <span slot="footer" class="dialog-footer">
        <el-button @click="setRightDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="allotRights">確 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    return {
      // 所有角色列表數(shù)據(jù)
      rolelist: [],
      // 控制分配權(quán)限對(duì)話(huà)框的顯示與隱藏
      setRightDialogVisible: false,
      // 所有權(quán)限的數(shù)據(jù)
      rightslist: [],
      // 樹(shù)形控件的屬性綁定對(duì)象
      treeProps: {
        label: 'authName',
        children: 'children'
      },
      // 默認(rèn)選中的節(jié)點(diǎn)Id值數(shù)組
      defKeys: [],
      // 當(dāng)前即將分配權(quán)限的角色id
      roleId: ''
    }
  },
  created() {
    this.getRolesList()
  },
  methods: {
    // 獲取所有角色的列表
    async getRolesList() {
      const { data: res } = await this.$http.get('roles')

      if (res.meta.status !== 200) {
        return this.$message.error('獲取角色列表失?。?)
      }

      this.rolelist = res.data

      console.log(this.rolelist)
    },
    // 根據(jù)Id刪除對(duì)應(yīng)的權(quán)限
    async removeRightById(role, rightId) {
      // 彈框提示用戶(hù)是否要?jiǎng)h除
      const confirmResult = await this.$confirm(
        '此操作將永久刪除該文件, 是否繼續(xù)?',
        '提示',
        {
          confirmButtonText: '確定',
          cancelButtonText: '取消',
          type: 'warning'
        }
      ).catch(err => err)

      if (confirmResult !== 'confirm') {
        return this.$message.info('取消了刪除!')
      }

      const { data: res } = await this.$http.delete(
        `roles/${role.id}/rights/${rightId}`
      )

      if (res.meta.status !== 200) {
        return this.$message.error('刪除權(quán)限失??!')
      }

      // this.getRolesList()
      role.children = res.data
    },
    // 展示分配權(quán)限的對(duì)話(huà)框
    async showSetRightDialog(role) {
      this.roleId = role.id
      // 獲取所有權(quán)限的數(shù)據(jù)
      const { data: res } = await this.$http.get('rights/tree')

      if (res.meta.status !== 200) {
        return this.$message.error('獲取權(quán)限數(shù)據(jù)失??!')
      }

      // 把獲取到的權(quán)限數(shù)據(jù)保存到 data 中
      this.rightslist = res.data
      console.log(this.rightslist)

      // 遞歸獲取三級(jí)節(jié)點(diǎn)的Id
      this.getLeafKeys(role, this.defKeys)

      this.setRightDialogVisible = true
    },
    // 通過(guò)遞歸的形式,獲取角色下所有三級(jí)權(quán)限的id,并保存到 defKeys 數(shù)組中
    getLeafKeys(node, arr) {
      // 如果當(dāng)前 node 節(jié)點(diǎn)不包含 children 屬性,則是三級(jí)節(jié)點(diǎn)
      if (!node.children) {
        return arr.push(node.id)
      }

      node.children.forEach(item => this.getLeafKeys(item, arr))
    },
    // 監(jiān)聽(tīng)分配權(quán)限對(duì)話(huà)框的關(guān)閉事件
    setRightDialogClosed() {
      this.defKeys = []
    },
    // 點(diǎn)擊為角色分配權(quán)限
    async allotRights() {
      const keys = [
        ...this.$refs.treeRef.getCheckedKeys(),
        ...this.$refs.treeRef.getHalfCheckedKeys()
      ]

      const idStr = keys.join(',')

      const { data: res } = await this.$http.post(
        `roles/${this.roleId}/rights`,
        { rids: idStr }
      )

      if (res.meta.status !== 200) {
        return this.$message.error('分配權(quán)限失敗!')
      }

      this.$message.success('分配權(quán)限成功!')
      this.getRolesList()
      this.setRightDialogVisible = false
    }
  }
}
</script>

<style lang="less" scoped>
.el-tag {
  margin: 7px;
}

.bdtop {
  border-top: 1px solid #eee;
}

.bdbottom {
  border-bottom: 1px solid #eee;
}

.vcenter {
  display: flex;
  align-items: center;
}
</style>

權(quán)限列表

權(quán)限列表對(duì)不同的權(quán)限做出展示,只發(fā)送一個(gè)請(qǐng)求即可獲取所有需要的數(shù)據(jù)

<template>
  <div>
    <!-- 面包屑導(dǎo)航區(qū)域 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">首頁(yè)</el-breadcrumb-item>
      <el-breadcrumb-item>權(quán)限管理</el-breadcrumb-item>
      <el-breadcrumb-item>權(quán)限列表</el-breadcrumb-item>
    </el-breadcrumb>

    <!-- 卡片視圖 -->
    <el-card>
      <el-table :data="rightsList" border stripe>
        <el-table-column type="index"></el-table-column>
        <el-table-column label="權(quán)限名稱(chēng)" prop="authName"></el-table-column>
        <el-table-column label="路徑" prop="path"></el-table-column>
        <el-table-column label="權(quán)限等級(jí)" prop="level">
          <template slot-scope="scope">
            <el-tag v-if="scope.row.level === '0'">一級(jí)</el-tag>
            <el-tag type="success" v-else-if="scope.row.level === '1'">二級(jí)</el-tag>
            <el-tag type="warning" v-else>三級(jí)</el-tag>
          </template>
        </el-table-column>
      </el-table>
    </el-card>
  </div>
</template>

<script>
export default {
  data() {
    return {
      // 權(quán)限列表
      rightsList: []
    }
  },
  created() {
    // 獲取所有的權(quán)限
    this.getRightsList()
  },
  methods: {
    // 獲取權(quán)限列表
    async getRightsList() {
      const { data: res } = await this.$http.get('rights/list')
      if (res.meta.status !== 200) {
        return this.$message.error('獲取權(quán)限列表失??!')
      }

      this.rightsList = res.data
      console.log(this.rightsList)
    }
  }
}
</script>

<style lang="less" scoped>
</style>

商品管理

商品分類(lèi)

<template>
  <div>
    <!-- 面包屑導(dǎo)航區(qū)域 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">首頁(yè)</el-breadcrumb-item>
      <el-breadcrumb-item>商品管理</el-breadcrumb-item>
      <el-breadcrumb-item>商品分類(lèi)</el-breadcrumb-item>
    </el-breadcrumb>

    <!-- 卡片視圖區(qū)域 -->
    <el-card>
      <el-row>
        <el-col>
          <el-button type="primary" @click="showAddCateDialog">添加分類(lèi)</el-button>
        </el-col>
      </el-row>

      <!-- 表格 -->
      <tree-table class="treeTable" :data="catelist" :columns="columns" :selection-type="false" :expand-type="false" show-index 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">一級(jí)</el-tag>
          <el-tag type="success" size="mini" v-else-if="scope.row.cat_level===1">二級(jí)</el-tag>
          <el-tag type="warning" size="mini" v-else>三級(jí)</el-tag>
        </template>
        <!-- 操作 -->
        <template slot="opt">
          <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>

      <!-- 分頁(yè)區(qū)域 -->
      <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="querInfo.pagenum" :page-sizes="[3, 5, 10, 15]" :page-size="querInfo.pagesize" layout="total, sizes, prev, pager, next, jumper" :total="total">
      </el-pagination>
    </el-card>

    <!-- 添加分類(lèi)的對(duì)話(huà)框 -->
    <el-dialog title="添加分類(lèi)" :visible.sync="addCateDialogVisible" width="50%" @close="addCateDialogClosed">
      <!-- 添加分類(lèi)的表單 -->
      <el-form :model="addCateForm" :rules="addCateFormRules" ref="addCateFormRef" label-width="100px">
        <el-form-item label="分類(lèi)名稱(chēng):" prop="cat_name">
          <el-input v-model="addCateForm.cat_name"></el-input>
        </el-form-item>
        <el-form-item label="父級(jí)分類(lèi):">
          <!-- options 用來(lái)指定數(shù)據(jù)源 -->
          <!-- props 用來(lái)指定配置對(duì)象 -->
          <el-cascader expand-trigger="hover" :options="parentCateList" :props="cascaderProps" v-model="selectedKeys" @change="parentCateChanged" clearable change-on-select>
          </el-cascader>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="addCateDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="addCate">確 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    return {
      // 查詢(xún)條件
      querInfo: {
        type: 3,
        pagenum: 1,
        pagesize: 5
      },
      // 商品分類(lèi)的數(shù)據(jù)列表,默認(rèn)為空
      catelist: [],
      // 總數(shù)據(jù)條數(shù)
      total: 0,
      // 為table指定列的定義
      columns: [
        {
          label: '分類(lèi)名稱(chēng)',
          prop: 'cat_name'
        },
        {
          label: '是否有效',
          // 表示,將當(dāng)前列定義為模板列
          type: 'template',
          // 表示當(dāng)前這一列使用模板名稱(chēng)
          template: 'isok'
        },
        {
          label: '排序',
          // 表示,將當(dāng)前列定義為模板列
          type: 'template',
          // 表示當(dāng)前這一列使用模板名稱(chēng)
          template: 'order'
        },
        {
          label: '操作',
          // 表示,將當(dāng)前列定義為模板列
          type: 'template',
          // 表示當(dāng)前這一列使用模板名稱(chēng)
          template: 'opt'
        }
      ],
      // 控制添加分類(lèi)對(duì)話(huà)框的顯示與隱藏
      addCateDialogVisible: false,
      // 添加分類(lèi)的表單數(shù)據(jù)對(duì)象
      addCateForm: {
        // 將要添加的分類(lèi)的名稱(chēng)
        cat_name: '',
        // 父級(jí)分類(lèi)的Id
        cat_pid: 0,
        // 分類(lèi)的等級(jí),默認(rèn)要添加的是1級(jí)分類(lèi)
        cat_level: 0
      },
      // 添加分類(lèi)表單的驗(yàn)證規(guī)則對(duì)象
      addCateFormRules: {
        cat_name: [{ required: true, message: '請(qǐng)輸入分類(lèi)名稱(chēng)', trigger: 'blur' }]
      },
      // 父級(jí)分類(lèi)的列表
      parentCateList: [],
      // 指定級(jí)聯(lián)選擇器的配置對(duì)象
      cascaderProps: {
        value: 'cat_id',
        label: 'cat_name',
        children: 'children'
      },
      // 選中的父級(jí)分類(lèi)的Id數(shù)組
      selectedKeys: []
    }
  },
  created() {
    this.getCateList()
  },
  methods: {
    // 獲取商品分類(lèi)數(shù)據(jù)
    async getCateList() {
      const { data: res } = await this.$http.get('categories', {
        params: this.querInfo
      })

      if (res.meta.status !== 200) {
        return this.$message.error('獲取商品分類(lèi)失??!')
      }

      console.log(res.data)
      // 把數(shù)據(jù)列表,賦值給 catelist
      this.catelist = res.data.result
      // 為總數(shù)據(jù)條數(shù)賦值
      this.total = res.data.total
    },
    // 監(jiān)聽(tīng) pagesize 改變
    handleSizeChange(newSize) {
      this.querInfo.pagesize = newSize
      this.getCateList()
    },
    // 監(jiān)聽(tīng) pagenum 改變
    handleCurrentChange(newPage) {
      this.querInfo.pagenum = newPage
      this.getCateList()
    },
    // 點(diǎn)擊按鈕,展示添加分類(lèi)的對(duì)話(huà)框
    showAddCateDialog() {
      // 先獲取父級(jí)分類(lèi)的數(shù)據(jù)列表
      this.getParentCateList()
      // 再展示出對(duì)話(huà)框
      this.addCateDialogVisible = true
    },
    // 獲取父級(jí)分類(lèi)的數(shù)據(jù)列表
    async getParentCateList() {
      const { data: res } = await this.$http.get('categories', {
        params: { type: 2 }
      })

      if (res.meta.status !== 200) {
        return this.$message.error('獲取父級(jí)分類(lèi)數(shù)據(jù)失?。?)
      }

      console.log(res.data)
      this.parentCateList = res.data
    },
    // 選擇項(xiàng)發(fā)生變化觸發(fā)這個(gè)函數(shù)
    parentCateChanged() {
      console.log(this.selectedKeys)
      // 如果 selectedKeys 數(shù)組中的 length 大于0,證明選中的父級(jí)分類(lèi)
      // 反之,就說(shuō)明沒(méi)有選中任何父級(jí)分類(lèi)
      if (this.selectedKeys.length > 0) {
        // 父級(jí)分類(lèi)的Id
        this.addCateForm.cat_pid = this.selectedKeys[this.selectedKeys.length - 1]
        // 為當(dāng)前分類(lèi)的等級(jí)賦值
        this.addCateForm.cat_level = this.selectedKeys.length
      } else {
        // 父級(jí)分類(lèi)的Id
        this.addCateForm.cat_pid = 0
        // 為當(dāng)前分類(lèi)的等級(jí)賦值
        this.addCateForm.cat_level = 0
      }
    },
    // 點(diǎn)擊按鈕,添加新的分類(lèi)
    addCate() {
      this.$refs.addCateFormRef.validate(async valid => {
        if (!valid) return
        const { data: res } = await this.$http.post('categories', this.addCateForm)

        if (res.meta.status !== 201) {
          return this.$message.error('添加分類(lèi)失?。?)
        }

        this.$message.success('添加分類(lèi)成功!')
        this.getCateList()
        this.addCateDialogVisible = false
      })
    },
    // 監(jiān)聽(tīng)對(duì)話(huà)框的關(guān)閉事件,重置表單數(shù)據(jù)
    addCateDialogClosed() {
      this.$refs.addCateFormRef.resetFields()
      this.selectedKeys = []
      this.addCateForm.cat_level = 0
      this.addCateForm.cat_pid = 0
    }
  }
}
</script>

<style lang="less" scoped>
.treeTable {
  margin-top: 15px;
}

.el-cascader {
  width: 100%;
}
</style>

商品列表

<template>
  <div>
    <!-- 面包屑導(dǎo)航區(qū)域 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">首頁(yè)</el-breadcrumb-item>
      <el-breadcrumb-item>商品管理</el-breadcrumb-item>
      <el-breadcrumb-item>商品列表</el-breadcrumb-item>
    </el-breadcrumb>

    <!-- 卡片視圖區(qū)域 -->
    <el-card>
      <el-row :gutter="20">
        <el-col :span="8">
          <el-input placeholder="請(qǐng)輸入內(nèi)容" 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">添加商品</el-button>
        </el-col>
      </el-row>

      <!-- table表格區(qū)域 -->
      <el-table :data="goodslist" border stripe>
        <el-table-column type="index"></el-table-column>
        <el-table-column label="商品名稱(chēng)" prop="goods_name"></el-table-column>
        <el-table-column label="商品價(jià)格(元)" prop="goods_price" width="95px"></el-table-column>
        <el-table-column label="商品重量" prop="goods_weight" width="70px"></el-table-column>
        <el-table-column label="創(chuàng)建時(shí)間" prop="add_time" width="140px">
          <template slot-scope="scope">
            {{scope.row.add_time | dateFormat}}
          </template>
        </el-table-column>
        <el-table-column label="操作" 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>

      <!-- 分頁(yè)區(qū)域 -->
      <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 {
      // 查詢(xún)參數(shù)對(duì)象
      queryInfo: {
        query: '',
        pagenum: 1,
        pagesize: 10
      },
      // 商品列表
      goodslist: [],
      // 總數(shù)據(jù)條數(shù)
      total: 0
    }
  },
  created() {
    this.getGoodsList()
  },
  methods: {
    // 根據(jù)分頁(yè)獲取對(duì)應(yīng)的商品列表
    async getGoodsList() {
      const { data: res } = await this.$http.get('goods', {
        params: this.queryInfo
      })

      if (res.meta.status !== 200) {
        return this.$message.error('獲取商品列表失??!')
      }

      this.$message.success('獲取商品列表成功!')
      console.log(res.data)
      this.goodslist = res.data.goods
      this.total = res.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(
        '此操作將永久刪除該商品, 是否繼續(xù)?',
        '提示',
        {
          confirmButtonText: '確定',
          cancelButtonText: '取消',
          type: 'warning'
        }
      ).catch(err => err)

      if (confirmResult !== 'confirm') {
        return this.$message.info('已經(jīng)取消刪除!')
      }

      const { data: res } = await this.$http.delete(`goods/${id}`)

      if (res.meta.status !== 200) {
        return this.$message.error('刪除失??!')
      }

      this.$message.success('刪除成功!')
      this.getGoodsList()
    },
    goAddpage() {
      this.$router.push('/goods/add')
    }
  }
}
</script>

<style lang="less" scoped>
</style>

增加商品

在商品分類(lèi)中點(diǎn)擊新增商品,則跳轉(zhuǎn)到新增商品窗口

vue電商后臺(tái)管理系統(tǒng),前端學(xué)習(xí),項(xiàng)目實(shí)戰(zhàn)案例以及bug處理,前端,1024程序員節(jié)

<template>
  <div>
    <!-- 面包屑導(dǎo)航區(qū)域 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">首頁(yè)</el-breadcrumb-item>
      <el-breadcrumb-item>商品管理</el-breadcrumb-item>
      <el-breadcrumb-item>添加商品</el-breadcrumb-item>
    </el-breadcrumb>

    <!-- 卡片視圖 -->
    <el-card>
      <!-- 提示區(qū)域 -->
      <el-alert title="添加商品信息" type="info" center show-icon :closable="false">
      </el-alert>
      <!-- 步驟條區(qū)域 -->
      <el-steps :space="200" :active="activeIndex - 0" finish-status="success" align-center>
        <el-step title="基本信息"></el-step>
        <el-step title="商品參數(shù)"></el-step>
        <el-step title="商品屬性"></el-step>
        <el-step title="商品圖片"></el-step>
        <el-step title="商品內(nèi)容"></el-step>
        <el-step title="完成"></el-step>
      </el-steps>

      <!-- tab欄區(qū)域 -->

      <el-form :model="addForm" :rules="addFormRules" ref="addFormRef" label-width="100px" label-position="top">
        <el-tabs v-model="activeIndex" :tab-position="'left'" :before-leave="beforeTabLeave" @tab-click="tabClicked">
          <el-tab-pane label="基本信息" name="0">
            <el-form-item label="商品名稱(chēng)" prop="goods_name">
              <el-input v-model="addForm.goods_name"></el-input>
            </el-form-item>
            <el-form-item label="商品價(jià)格" prop="goods_price">
              <el-input v-model="addForm.goods_price" type="number"></el-input>
            </el-form-item>
            <el-form-item label="商品重量" prop="goods_weight">
              <el-input v-model="addForm.goods_weight" type="number"></el-input>
            </el-form-item>
            <el-form-item label="商品數(shù)量" prop="goods_number">
              <el-input v-model="addForm.goods_number" type="number"></el-input>
            </el-form-item>
            <el-form-item label="商品分類(lèi)" prop="goods_cat">
              <el-cascader expand-trigger="hover" :options="catelist" :props="cateProps" v-model="addForm.goods_cat" @change="handleChange">
              </el-cascader>
            </el-form-item>
          </el-tab-pane>
          <el-tab-pane label="商品參數(shù)" name="1">
            <!-- 渲染表單的Item項(xiàng) -->
            <el-form-item :label="item.attr_name" v-for="item in manyTableData" :key="item.attr_id">
              <!-- 復(fù)選框組 -->
              <el-checkbox-group v-model="item.attr_vals">
                <el-checkbox :label="cb" v-for="(cb, i) in item.attr_vals" :key="i" border></el-checkbox>
              </el-checkbox-group>
            </el-form-item>
          </el-tab-pane>
          <el-tab-pane label="商品屬性" 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>
          <el-tab-pane label="商品圖片" name="3">
            <!-- action 表示圖片要上傳到的后臺(tái)API地址 -->
            <el-upload :action="uploadURL" :on-preview="handlePreview" :on-remove="handleRemove" list-type="picture" :headers="headerObj" :on-success="handleSuccess">
              <el-button size="small" type="primary">點(diǎn)擊上傳</el-button>
            </el-upload>
          </el-tab-pane>
          <el-tab-pane label="商品內(nèi)容" name="4">
            <!-- 富文本編輯器組件 -->
            <quill-editor v-model="addForm.goods_introduce"></quill-editor>
            <!-- 添加商品的按鈕 -->
            <el-button type="primary" class="btnAdd" @click="add">添加商品</el-button>
          </el-tab-pane>
        </el-tabs>
      </el-form>

    </el-card>

    <!-- 圖片預(yù)覽 -->
    <el-dialog title="圖片預(yù)覽" :visible.sync="previewVisible" width="50%">
      <img :src="previewPath" alt="" class="previewImg">
    </el-dialog>
  </div>
</template>

<script>
import _ from 'lodash'

export default {
  data() {
    return {
      activeIndex: '0',
      // 添加商品的表單數(shù)據(jù)對(duì)象
      addForm: {
        goods_name: '',
        goods_price: 0,
        goods_weight: 0,
        goods_number: 0,
        // 商品所屬的分類(lèi)數(shù)組
        goods_cat: [],
        // 圖片的數(shù)組
        pics: [],
        // 商品的詳情描述
        goods_introduce: '',
        attrs: []
      },
      addFormRules: {
        goods_name: [
          { required: true, message: '請(qǐng)輸入商品名稱(chēng)', trigger: 'blur' }
        ],
        goods_price: [
          { required: true, message: '請(qǐng)輸入商品價(jià)格', trigger: 'blur' }
        ],
        goods_weight: [
          { required: true, message: '請(qǐng)輸入商品重量', trigger: 'blur' }
        ],
        goods_number: [
          { required: true, message: '請(qǐng)輸入商品數(shù)量', trigger: 'blur' }
        ],
        goods_cat: [
          { required: true, message: '請(qǐng)選擇商品分類(lèi)', trigger: 'blur' }
        ]
      },
      // 商品分類(lèi)列表
      catelist: [],
      cateProps: {
        label: 'cat_name',
        value: 'cat_id',
        children: 'children'
      },
      // 動(dòng)態(tài)參數(shù)列表數(shù)據(jù)
      manyTableData: [],
      // 靜態(tài)屬性列表數(shù)據(jù)
      onlyTableData: [],
      // 上傳圖片的URL地址
      uploadURL: 'http://127.0.0.1:8888/api/private/v1/upload',
      // 圖片上傳組件的headers請(qǐng)求頭對(duì)象
      headerObj: {
        Authorization: window.sessionStorage.getItem('token')
      },
      previewPath: '',
      previewVisible: false
    }
  },
  created() {
    this.getCateList()
  },
  methods: {
    // 獲取所有商品分類(lèi)數(shù)據(jù)
    async getCateList() {
      const { data: res } = await this.$http.get('categories')

      if (res.meta.status !== 200) {
        return this.$message.error('獲取商品分類(lèi)數(shù)據(jù)失敗!')
      }

      this.catelist = res.data
      console.log(this.catelist)
    },
    // 級(jí)聯(lián)選擇器選中項(xiàng)變化,會(huì)觸發(fā)這個(gè)函數(shù)
    handleChange() {
      console.log(this.addForm.goods_cat)
      if (this.addForm.goods_cat.length !== 3) {
        this.addForm.goods_cat = []
      }
    },
    beforeTabLeave(activeName, oldActiveName) {
      // console.log('即將離開(kāi)的標(biāo)簽頁(yè)名字是:' + oldActiveName)
      // console.log('即將進(jìn)入的標(biāo)簽頁(yè)名字是:' + activeName)
      // return false
      if (oldActiveName === '0' && this.addForm.goods_cat.length !== 3) {
        this.$message.error('請(qǐng)先選擇商品分類(lèi)!')
        return false
      }
    },
    async tabClicked() {
      // console.log(this.activeIndex)
      // 證明訪(fǎng)問(wèn)的是動(dòng)態(tài)參數(shù)面板
      if (this.activeIndex === '1') {
        const { data: res } = await this.$http.get(
          `categories/${this.cateId}/attributes`,
          {
            params: { sel: 'many' }
          }
        )

        if (res.meta.status !== 200) {
          return this.$message.error('獲取動(dòng)態(tài)參數(shù)列表失?。?)
        }

        console.log(res.data)
        res.data.forEach(item => {
          item.attr_vals =
            item.attr_vals.length === 0 ? [] : item.attr_vals.split(' ')
        })
        this.manyTableData = res.data
      } else if (this.activeIndex === '2') {
        const { data: res } = await this.$http.get(
          `categories/${this.cateId}/attributes`,
          {
            params: { sel: 'only' }
          }
        )

        if (res.meta.status !== 200) {
          return this.$message.error('獲取靜態(tài)屬性失??!')
        }

        console.log(res.data)
        this.onlyTableData = res.data
      }
    },
    // 處理圖片預(yù)覽效果
    handlePreview(file) {
      console.log(file)
      this.previewPath = file.response.data.url
      this.previewVisible = true
    },
    // 處理移除圖片的操作
    handleRemove(file) {
      // console.log(file)
      // 1. 獲取將要?jiǎng)h除的圖片的臨時(shí)路徑
      const filePath = file.response.data.tmp_path
      // 2. 從 pics 數(shù)組中,找到這個(gè)圖片對(duì)應(yīng)的索引值
      const i = this.addForm.pics.findIndex(x => x.pic === filePath)
      // 3. 調(diào)用數(shù)組的 splice 方法,把圖片信息對(duì)象,從 pics 數(shù)組中移除
      this.addForm.pics.splice(i, 1)
      console.log(this.addForm)
    },
    // 監(jiān)聽(tīng)圖片上傳成功的事件
    handleSuccess(response) {
      console.log(response)
      // 1. 拼接得到一個(gè)圖片信息對(duì)象
      const picInfo = { pic: response.data.tmp_path }
      // 2. 將圖片信息對(duì)象,push 到pics數(shù)組中
      this.addForm.pics.push(picInfo)
      console.log(this.addForm)
    },
    // 添加商品
    add() {
      this.$refs.addFormRef.validate(async valid => {
        if (!valid) {
          return this.$message.error('請(qǐng)?zhí)顚?xiě)必要的表單項(xiàng)!')
        }
        // 執(zhí)行添加的業(yè)務(wù)邏輯
        // lodash   cloneDeep(obj)
        const form = _.cloneDeep(this.addForm)
        form.goods_cat = form.goods_cat.join(',')
        // 處理動(dòng)態(tài)參數(shù)
        this.manyTableData.forEach(item => {
          const newInfo = {
            attr_id: item.attr_id,
            attr_value: item.attr_vals.join(' ')
          }
          this.addForm.attrs.push(newInfo)
        })
        // 處理靜態(tài)屬性
        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
        console.log(form)

        // 發(fā)起請(qǐng)求添加商品
        // 商品的名稱(chēng),必須是唯一的
        const { data: res } = await this.$http.post('goods', form)

        if (res.meta.status !== 201) {
          return this.$message.error('添加商品失?。?)
        }

        this.$message.success('添加商品成功!')
        this.$router.push('/goods')
      })
    }
  },
  computed: {
    cateId() {
      if (this.addForm.goods_cat.length === 3) {
        return this.addForm.goods_cat[2]
      }
      return null
    }
  }
}
</script>

<style lang="less" scoped>
.el-checkbox {
  margin: 0 10px 0 0 !important;
}

.previewImg {
  width: 100%;
}

.btnAdd {
  margin-top: 15px;
}
</style>

分類(lèi)參數(shù)

在分類(lèi)參數(shù)中選擇一件商品,可以為其添加靜態(tài)或者動(dòng)態(tài)參數(shù),這個(gè)參數(shù)可以展示在移動(dòng)端商品的屬性中。

vue電商后臺(tái)管理系統(tǒng),前端學(xué)習(xí),項(xiàng)目實(shí)戰(zhàn)案例以及bug處理,前端,1024程序員節(jié)

<template>
  <div>
    <!-- 面包屑導(dǎo)航區(qū)域 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">首頁(yè)</el-breadcrumb-item>
      <el-breadcrumb-item>商品管理</el-breadcrumb-item>
      <el-breadcrumb-item>參數(shù)列表</el-breadcrumb-item>
    </el-breadcrumb>

    <!-- 卡片視圖區(qū)域 -->
    <el-card>
      <!-- 警告區(qū)域 -->
      <el-alert show-icon title="注意:只允許為第三級(jí)分類(lèi)設(shè)置相關(guān)參數(shù)!" type="warning" :closable="false"></el-alert>

      <!-- 選擇商品分類(lèi)區(qū)域 -->
      <el-row class="cat_opt">
        <el-col>
          <span>選擇商品分類(lèi):</span>
          <!-- 選擇商品分類(lèi)的級(jí)聯(lián)選擇框 -->
          <el-cascader expand-trigger="hover" :options="catelist" :props="cateProps" v-model="selectedCateKeys" @change="handleChange">
          </el-cascader>
        </el-col>
      </el-row>

      <!-- tab 頁(yè)簽區(qū)域 -->
      <el-tabs v-model="activeName" @tab-click="handleTabClick">
        <!-- 添加動(dòng)態(tài)參數(shù)的面板 -->
        <el-tab-pane label="動(dòng)態(tài)參數(shù)" name="many">
          <!-- 添加參數(shù)的按鈕 -->
          <el-button type="primary" size="mini" :disabled="isBtnDisabled" @click="addDialogVisible=true">添加參數(shù)</el-button>
          <!-- 動(dòng)態(tài)參數(shù)表格 -->
          <el-table :data="manyTableData" border stripe>
            <!-- 展開(kāi)行 -->
            <el-table-column type="expand">
              <template slot-scope="scope">
                <!-- 循環(huán)渲染Tag標(biāo)簽 -->
                <el-tag v-for="(item, i) in scope.row.attr_vals" :key="i" closable @close="handleClose(i, scope.row)">{{item}}</el-tag>
                <!-- 輸入的文本框 -->
                <el-input class="input-new-tag" v-if="scope.row.inputVisible" v-model="scope.row.inputValue" ref="saveTagInput" size="small" @keyup.enter.native="handleInputConfirm(scope.row)" @blur="handleInputConfirm(scope.row)">
                </el-input>
                <!-- 添加按鈕 -->
                <el-button v-else class="button-new-tag" size="small" @click="showInput(scope.row)">+ New Tag</el-button>
              </template>
            </el-table-column>
            <!-- 索引列 -->
            <el-table-column type="index"></el-table-column>
            <el-table-column label="參數(shù)名稱(chēng)" prop="attr_name"></el-table-column>
            <el-table-column label="操作">
              <template slot-scope="scope">
                <el-button size="mini" type="primary" icon="el-icon-edit" @click="showEditDialog(scope.row.attr_id)">編輯</el-button>
                <el-button size="mini" type="danger" icon="el-icon-delete" @click="removeParams(scope.row.attr_id)">刪除</el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-tab-pane>
        <!-- 添加靜態(tài)屬性的面板 -->
        <el-tab-pane label="靜態(tài)屬性" name="only">
          <!-- 添加屬性的按鈕 -->
          <el-button type="primary" size="mini" :disabled="isBtnDisabled" @click="addDialogVisible=true">添加屬性</el-button>
          <!-- 靜態(tài)屬性表格 -->
          <el-table :data="onlyTableData" border stripe>
            <!-- 展開(kāi)行 -->
            <el-table-column type="expand">
              <template slot-scope="scope">
                <!-- 循環(huán)渲染Tag標(biāo)簽 -->
                <el-tag v-for="(item, i) in scope.row.attr_vals" :key="i" closable @close="handleClose(i, scope.row)">{{item}}</el-tag>
                <!-- 輸入的文本框 -->
                <el-input class="input-new-tag" v-if="scope.row.inputVisible" v-model="scope.row.inputValue" ref="saveTagInput" size="small" @keyup.enter.native="handleInputConfirm(scope.row)" @blur="handleInputConfirm(scope.row)">
                </el-input>
                <!-- 添加按鈕 -->
                <el-button v-else class="button-new-tag" size="small" @click="showInput(scope.row)">+ New Tag</el-button>
              </template>
            </el-table-column>
            <!-- 索引列 -->
            <el-table-column type="index"></el-table-column>
            <el-table-column label="屬性名稱(chēng)" prop="attr_name"></el-table-column>
            <el-table-column label="操作">
              <template slot-scope="scope">
                <el-button size="mini" type="primary" icon="el-icon-edit" @click="showEditDialog(scope.row.attr_id)">編輯</el-button>
                <el-button size="mini" type="danger" icon="el-icon-delete" @click="removeParams(scope.row.attr_id)">刪除</el-button>
              </template>
            </el-table-column>
          </el-table>
        </el-tab-pane>
      </el-tabs>
    </el-card>

    <!-- 添加參數(shù)的對(duì)話(huà)框 -->
    <el-dialog :title="'添加' + titleText" :visible.sync="addDialogVisible" width="50%" @close="addDialogClosed">
      <!-- 添加參數(shù)的對(duì)話(huà)框 -->
      <el-form :model="addForm" :rules="addFormRules" ref="addFormRef" label-width="100px">
        <el-form-item :label="titleText" prop="attr_name">
          <el-input v-model="addForm.attr_name"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="addDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="addParams">確 定</el-button>
      </span>
    </el-dialog>

    <!-- 修改參數(shù)的對(duì)話(huà)框 -->
    <el-dialog :title="'修改' + titleText" :visible.sync="editDialogVisible" width="50%" @close="editDialogClosed">
      <!-- 添加參數(shù)的對(duì)話(huà)框 -->
      <el-form :model="editForm" :rules="editFormRules" ref="editFormRef" label-width="100px">
        <el-form-item :label="titleText" prop="attr_name">
          <el-input v-model="editForm.attr_name"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="editDialogVisible = false">取 消</el-button>
        <el-button type="primary" @click="editParams">確 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
export default {
  data() {
    return {
      // 商品分類(lèi)列表
      catelist: [],
      // 級(jí)聯(lián)選擇框的配置對(duì)象
      cateProps: {
        value: 'cat_id',
        label: 'cat_name',
        children: 'children'
      },
      // 級(jí)聯(lián)選擇框雙向綁定到的數(shù)組
      selectedCateKeys: [],
      // 被激活的頁(yè)簽的名稱(chēng)
      activeName: 'many',
      // 動(dòng)態(tài)參數(shù)的數(shù)據(jù)
      manyTableData: [],
      // 靜態(tài)屬性的數(shù)據(jù)
      onlyTableData: [],
      // 控制添加對(duì)話(huà)框的顯示與隱藏
      addDialogVisible: false,
      // 添加參數(shù)的表單數(shù)據(jù)對(duì)象
      addForm: {
        attr_name: ''
      },
      // 添加表單的驗(yàn)證規(guī)則對(duì)象
      addFormRules: {
        attr_name: [
          { required: true, message: '請(qǐng)輸入?yún)?shù)名稱(chēng)', trigger: 'blur' }
        ]
      },
      // 控制修改對(duì)話(huà)框的顯示與隱藏
      editDialogVisible: false,
      // 修改的表單數(shù)據(jù)對(duì)象
      editForm: {},
      // 修改表單的驗(yàn)證規(guī)則對(duì)象
      editFormRules: {
        attr_name: [
          { required: true, message: '請(qǐng)輸入?yún)?shù)名稱(chēng)', trigger: 'blur' }
        ]
      }
    }
  },
  created() {
    this.getCateList()
  },
  methods: {
    // 獲取所有的商品分類(lèi)列表
    async getCateList() {
      const { data: res } = await this.$http.get('categories')
      if (res.meta.status !== 200) {
        return this.$message.error('獲取商品分類(lèi)失??!')
      }

      this.catelist = res.data

      console.log(this.catelist)
    },
    // 級(jí)聯(lián)選擇框選中項(xiàng)變化,會(huì)觸發(fā)這個(gè)函數(shù)
    handleChange() {
      this.getParamsData()
    },
    // tab 頁(yè)簽點(diǎn)擊事件的處理函數(shù)
    handleTabClick() {
      console.log(this.activeName)
      this.getParamsData()
    },
    // 獲取參數(shù)的列表數(shù)據(jù)
    async getParamsData() {
      // 證明選中的不是三級(jí)分類(lèi)
      if (this.selectedCateKeys.length !== 3) {
        this.selectedCateKeys = []
        this.manyTableData = []
        this.onlyTableData = []
        return
      }

      // 證明選中的是三級(jí)分類(lèi)
      console.log(this.selectedCateKeys)
      // 根據(jù)所選分類(lèi)的Id,和當(dāng)前所處的面板,獲取對(duì)應(yīng)的參數(shù)
      const { data: res } = await this.$http.get(
        `categories/${this.cateId}/attributes`,
        {
          params: { sel: this.activeName }
        }
      )

      if (res.meta.status !== 200) {
        return this.$message.error('獲取參數(shù)列表失敗!')
      }

      res.data.forEach(item => {
        item.attr_vals = item.attr_vals ? item.attr_vals.split(' ') : []
        // 控制文本框的顯示與隱藏
        item.inputVisible = false
        // 文本框中輸入的值
        item.inputValue = ''
      })

      console.log(res.data)
      if (this.activeName === 'many') {
        this.manyTableData = res.data
      } else {
        this.onlyTableData = res.data
      }
    },
    // 監(jiān)聽(tīng)添加對(duì)話(huà)框的關(guān)閉事件
    addDialogClosed() {
      this.$refs.addFormRef.resetFields()
    },
    // 點(diǎn)擊按鈕,添加參數(shù)
    addParams() {
      this.$refs.addFormRef.validate(async valid => {
        if (!valid) return
        const { data: res } = await this.$http.post(
          `categories/${this.cateId}/attributes`,
          {
            attr_name: this.addForm.attr_name,
            attr_sel: this.activeName
          }
        )

        if (res.meta.status !== 201) {
          return this.$message.error('添加參數(shù)失??!')
        }

        this.$message.success('添加參數(shù)成功!')
        this.addDialogVisible = false
        this.getParamsData()
      })
    },
    // 點(diǎn)擊按鈕,展示修改的對(duì)話(huà)框
    async showEditDialog(attrId) {
      // 查詢(xún)當(dāng)前參數(shù)的信息
      const { data: res } = await this.$http.get(
        `categories/${this.cateId}/attributes/${attrId}`,
        {
          params: { attr_sel: this.activeName }
        }
      )

      if (res.meta.status !== 200) {
        return this.$message.error('獲取參數(shù)信息失??!')
      }

      this.editForm = res.data
      this.editDialogVisible = true
    },
    // 重置修改的表單
    editDialogClosed() {
      this.$refs.editFormRef.resetFields()
    },
    // 點(diǎn)擊按鈕,修改參數(shù)信息
    editParams() {
      this.$refs.editFormRef.validate(async valid => {
        if (!valid) return
        const { data: res } = await this.$http.put(
          `categories/${this.cateId}/attributes/${this.editForm.attr_id}`,
          { attr_name: this.editForm.attr_name, attr_sel: this.activeName }
        )

        if (res.meta.status !== 200) {
          return this.$message.error('修改參數(shù)失?。?)
        }

        this.$message.success('修改參數(shù)成功!')
        this.getParamsData()
        this.editDialogVisible = false
      })
    },
    // 根據(jù)Id刪除對(duì)應(yīng)的參數(shù)項(xiàng)
    async removeParams(attrId) {
      const confirmResult = await this.$confirm(
        '此操作將永久刪除該參數(shù), 是否繼續(xù)?',
        '提示',
        {
          confirmButtonText: '確定',
          cancelButtonText: '取消',
          type: 'warning'
        }
      ).catch(err => err)

      // 用戶(hù)取消了刪除的操作
      if (confirmResult !== 'confirm') {
        return this.$message.info('已取消刪除!')
      }

      // 刪除的業(yè)務(wù)邏輯
      const { data: res } = await this.$http.delete(
        `categories/${this.cateId}/attributes/${attrId}`
      )

      if (res.meta.status !== 200) {
        return this.$message.error('刪除參數(shù)失敗!')
      }

      this.$message.success('刪除參數(shù)成功!')
      this.getParamsData()
    },
    // 文本框失去焦點(diǎn),或摁下了 Enter 都會(huì)觸發(fā)
    async handleInputConfirm(row) {
      if (row.inputValue.trim().length === 0) {
        row.inputValue = ''
        row.inputVisible = false
        return
      }
      // 如果沒(méi)有return,則證明輸入的內(nèi)容,需要做后續(xù)處理
      row.attr_vals.push(row.inputValue.trim())
      row.inputValue = ''
      row.inputVisible = false
      // 需要發(fā)起請(qǐng)求,保存這次操作
      this.saveAttrVals(row)
    },
    // 將對(duì) attr_vals 的操作,保存到數(shù)據(jù)庫(kù)
    async saveAttrVals(row) {
      // 需要發(fā)起請(qǐng)求,保存這次操作
      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(' ')
        }
      )

      if (res.meta.status !== 200) {
        return this.$message.error('修改參數(shù)項(xiàng)失??!')
      }

      this.$message.success('修改參數(shù)項(xiàng)成功!')
    },
    // 點(diǎn)擊按鈕,展示文本輸入框
    showInput(row) {
      row.inputVisible = true
      // 讓文本框自動(dòng)獲得焦點(diǎn)
      // $nextTick 方法的作用,就是當(dāng)頁(yè)面上元素被重新渲染之后,才會(huì)指定回調(diào)函數(shù)中的代碼
      this.$nextTick(_ => {
        this.$refs.saveTagInput.$refs.input.focus()
      })
    },
    // 刪除對(duì)應(yīng)的參數(shù)可選項(xiàng)
    handleClose(i, row) {
      row.attr_vals.splice(i, 1)
      this.saveAttrVals(row)
    }
  },
  computed: {
    // 如果按鈕需要被禁用,則返回true,否則返回false
    isBtnDisabled() {
      if (this.selectedCateKeys.length !== 3) {
        return true
      }
      return false
    },
    // 當(dāng)前選中的三級(jí)分類(lèi)的Id
    cateId() {
      if (this.selectedCateKeys.length === 3) {
        return this.selectedCateKeys[2]
      }
      return null
    },
    // 動(dòng)態(tài)計(jì)算標(biāo)題的文本
    titleText() {
      if (this.activeName === 'many') {
        return '動(dòng)態(tài)參數(shù)'
      }
      return '靜態(tài)屬性'
    }
  }
}
</script>

<style lang="less" scoped>
.cat_opt {
  margin: 15px 0;
}

.el-tag {
  margin: 10px;
}

.input-new-tag {
  width: 120px;
}
</style>

訂單管理

訂單列表

訂單管理的實(shí)現(xiàn)和用戶(hù)管理有很多類(lèi)似的地方,都是向后端發(fā)送請(qǐng)求然后渲染到頁(yè)面上

<template>
  <div>
    <!-- 面包屑導(dǎo)航區(qū)域 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">首頁(yè)</el-breadcrumb-item>
      <el-breadcrumb-item>訂單管理</el-breadcrumb-item>
      <el-breadcrumb-item>訂單列表</el-breadcrumb-item>
    </el-breadcrumb>

    <!-- 卡片視圖區(qū)域 -->
    <el-card>
      <el-row>
        <el-col :span="8">
          <el-input placeholder="請(qǐng)輸入內(nèi)容">
            <el-button slot="append" icon="el-icon-search"></el-button>
          </el-input>
        </el-col>
      </el-row>

      <!-- 訂單列表數(shù)據(jù) -->
      <el-table :data="orderlist" border stripe>
        <el-table-column type="index"></el-table-column>
        <el-table-column label="訂單編號(hào)" prop="order_number"></el-table-column>
        <el-table-column label="訂單價(jià)格" prop="order_price"></el-table-column>
        <el-table-column label="是否付款" prop="pay_status">
          <template slot-scope="scope">
            <el-tag type="success" v-if="scope.row.pay_status === '1'">已付款</el-tag>
            <el-tag type="danger" v-else>未付款</el-tag>
          </template>
        </el-table-column>
        <el-table-column label="是否發(fā)貨" prop="is_send">
          <template slot-scope="scope">
            <template>
              {{scope.row.is_send}}
            </template>
          </template>
        </el-table-column>
        <el-table-column label="下單時(shí)間" prop="create_time">
          <template slot-scope="scope">
            {{scope.row.create_time | dateFormat}}
          </template>
        </el-table-column>
        <el-table-column label="操作">
          <template>
            <el-button size="mini" type="primary" icon="el-icon-edit" @click="showBox"></el-button>
            <el-button size="mini" type="success" icon="el-icon-location" @click="showProgressBox"></el-button>
          </template>
        </el-table-column>
      </el-table>

      <!-- 分頁(yè)區(qū)域 -->
      <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="queryInfo.pagenum" :page-sizes="[5, 10, 15]" :page-size="queryInfo.pagesize" layout="total, sizes, prev, pager, next, jumper" :total="total">
      </el-pagination>
    </el-card>

    <!-- 修改地址的對(duì)話(huà)框 -->
    <el-dialog title="修改地址" :visible.sync="addressVisible" width="50%" @close="addressDialogClosed">
      <el-form :model="addressForm" :rules="addressFormRules" ref="addressFormRef" label-width="100px">
        <el-form-item label="省市區(qū)/縣" prop="address1">
          <el-cascader :options="cityData" v-model="addressForm.address1"></el-cascader>
        </el-form-item>
        <el-form-item label="詳細(xì)地址" prop="address2">
          <el-input v-model="addressForm.address2"></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button @click="addressVisible = false">取 消</el-button>
        <el-button type="primary" @click="addressVisible = false">確 定</el-button>
      </span>
    </el-dialog>

    <!-- 展示物流進(jìn)度的對(duì)話(huà)框 -->
    <el-dialog title="物流進(jìn)度" :visible.sync="progressVisible" width="50%">
      <!-- 時(shí)間線(xiàn) -->
      <el-timeline>
        <el-timeline-item v-for="(activity, index) in progressInfo" :key="index" :timestamp="activity.time">
          {{activity.context}}
        </el-timeline-item>
      </el-timeline>
    </el-dialog>
  </div>
</template>

<script>
import cityData from './citydata.js'

export default {
  data() {
    return {
      queryInfo: {
        query: '',
        pagenum: 1,
        pagesize: 10
      },
      total: 0,
      orderlist: [],
      addressVisible: false,
      addressForm: {
        address1: [],
        address2: ''
      },
      addressFormRules: {
        address1: [
          { required: true, message: '請(qǐng)選擇省市區(qū)縣', trigger: 'blur' }
        ],
        address2: [
          { required: true, message: '請(qǐng)?zhí)顚?xiě)詳細(xì)地址', trigger: 'blur' }
        ]
      },
      cityData,
      progressVisible: false,
      progressInfo: []
    }
  },
  created() {
    this.getOrderList()
  },
  methods: {
    async getOrderList() {
      const { data: res } = await this.$http.get('orders', {
        params: this.queryInfo
      })

      if (res.meta.status !== 200) {
        return this.$message.error('獲取訂單列表失??!')
      }

      console.log(res)
      this.total = res.data.total
      this.orderlist = res.data.goods
    },
    handleSizeChange(newSize) {
      this.queryInfo.pagesize = newSize
      this.getOrderList()
    },
    handleCurrentChange(newPage) {
      this.queryInfo.pagenum = newPage
      this.getOrderList()
    },
    // 展示修改地址的對(duì)話(huà)框
    showBox() {
      this.addressVisible = true
    },
    addressDialogClosed() {
      this.$refs.addressFormRef.resetFields()
    },
    async showProgressBox() {
      const { data: res } = await this.$http.get('/kuaidi/804909574412544580')

      if (res.meta.status !== 200) {
        return this.$message.error('獲取物流進(jìn)度失敗!')
      }

      this.progressInfo = res.data

      this.progressVisible = true
      console.log(this.progressInfo)
    }
  }
}
</script>

<style lang="less" scoped>
@import '../../plugins/timeline/timeline.css';
@import '../../plugins/timeline-item/timeline-item.css';

.el-cascader {
  width: 100%;
}
</style>

數(shù)據(jù)統(tǒng)計(jì)

數(shù)據(jù)報(bào)表

數(shù)據(jù)統(tǒng)計(jì)部分用到了echarts,從后端獲得數(shù)據(jù)后通過(guò)?_.merge()將數(shù)據(jù)組合在一起,最后渲染在頁(yè)面上

<template>
  <div>
    <!-- 面包屑導(dǎo)航區(qū)域 -->
    <el-breadcrumb separator-class="el-icon-arrow-right">
      <el-breadcrumb-item :to="{ path: '/home' }">首頁(yè)</el-breadcrumb-item>
      <el-breadcrumb-item>數(shù)據(jù)統(tǒng)計(jì)</el-breadcrumb-item>
      <el-breadcrumb-item>數(shù)據(jù)報(bào)表</el-breadcrumb-item>
    </el-breadcrumb>

    <!-- 卡片視圖區(qū)域 -->
    <el-card>
      <!-- 2. 為ECharts準(zhǔn)備一個(gè)具備大?。▽捀撸┑腄om -->
      <div id="main" style="width: 750px;height:400px;"></div>
    </el-card>
  </div>
</template>

<script>
// 1. 導(dǎo)入 echarts
import echarts from 'echarts'
import _ from 'lodash'

export default {
  data() {
    return {
      // 需要合并的數(shù)據(jù)
      options: {
        title: {
          text: '用戶(hù)來(lái)源'
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'cross',
            label: {
              backgroundColor: '#E9EEF3'
            }
          }
        },
        grid: {
          left: '3%',
          right: '4%',
          bottom: '3%',
          containLabel: true
        },
        xAxis: [
          {
            boundaryGap: false
          }
        ],
        yAxis: [
          {
            type: 'value'
          }
        ]
      }
    }
  },
  created() {},
  // 此時(shí),頁(yè)面上的元素,已經(jīng)被渲染完畢了!
  async mounted() {
    // 3. 基于準(zhǔn)備好的dom,初始化echarts實(shí)例
    var myChart = echarts.init(document.getElementById('main'))

    const { data: res } = await this.$http.get('reports/type/1')
    if (res.meta.status !== 200) {
      return this.$message.error('獲取折線(xiàn)圖數(shù)據(jù)失?。?)
    }

    // 4. 準(zhǔn)備數(shù)據(jù)和配置項(xiàng)
    const result = _.merge(res.data, this.options)

    // 5. 展示數(shù)據(jù)
    myChart.setOption(result)
  },
  methods: {}
}
</script>

<style lang="less" scoped>
</style>

項(xiàng)目git地址

目錄中有后端以及sql文件,按照說(shuō)明運(yùn)行即可

電商系統(tǒng)前端: 電商管理系統(tǒng)前端

學(xué)習(xí)資源

黑馬程序員前端文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-777192.html

到了這里,關(guān)于vue項(xiàng)目實(shí)戰(zhàn)-電商后臺(tái)管理系統(tǒng)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶(hù)投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Vue3.2 + TypeScript + Pinia + Vite4 + Element-Plus + 微前端(qiankun) 后臺(tái)管理系統(tǒng)模板(已開(kāi)源---顯示項(xiàng)目頁(yè)面截圖)

    Vue3.2 + TypeScript + Pinia + Vite4 + Element-Plus + 微前端(qiankun) 后臺(tái)管理系統(tǒng)模板(已開(kāi)源---顯示項(xiàng)目頁(yè)面截圖)

    Wocwin-Admin,是基于 Vue3.2、TypeScript、Vite、Pinia、Element-Plus、Qiankun(微前端) 開(kāi)源的一套后臺(tái)管理模板;同時(shí)集成了微前端 qiankun也可以當(dāng)做一個(gè)子應(yīng)用。項(xiàng)目中組件頁(yè)面使用了Element-plus 二次封裝 t-ui-plus 組件,目前已新增fastmock接口。 Link:https://wocwin.github.io/wocwin-admin/ 賬號(hào):

    2024年02月08日
    瀏覽(40)
  • vue項(xiàng)目-后臺(tái)管理系統(tǒng)

    前言: 一個(gè)傳唱度極高的前端項(xiàng)目,及其適合像博主這樣的小白練手。特以此文章記錄下項(xiàng)目基本的創(chuàng)作思路,并且文末附贈(zèng)項(xiàng)目源碼,思維導(dǎo)圖及一些后臺(tái)文件,有興趣可自取。希望對(duì)朋友們有用。 結(jié)構(gòu): 一,登錄頁(yè) 二,主頁(yè)面 1,用戶(hù)管理 用戶(hù)列表 2,權(quán)限管理 角色列

    2024年02月16日
    瀏覽(17)
  • Vue + ElementUI 實(shí)現(xiàn)后臺(tái)管理系統(tǒng)模板 -- 前端篇

    Vue + ElementUI 實(shí)現(xiàn)后臺(tái)管理系統(tǒng)模板 -- 前端篇

    使用場(chǎng)景分析: Home.vue 頁(yè)面中,Header 部分有個(gè)折疊按鈕,點(diǎn)擊之后,可以折疊與展開(kāi) Aside 組件,這之間就設(shè)計(jì)到數(shù)據(jù)在組件間的共享。 使用 vuex 后,數(shù)據(jù)統(tǒng)一管理,當(dāng)數(shù)據(jù)發(fā)生變化時(shí),其所有引用的地方均會(huì)修改。 2、安裝、模塊化使用 vuex 1》安裝 項(xiàng)目構(gòu)建時(shí),已經(jīng)安裝

    2024年04月11日
    瀏覽(24)
  • Vite-Admin后臺(tái)管理系統(tǒng)|vite4+vue3+pinia前端后臺(tái)框架實(shí)例

    Vite-Admin后臺(tái)管理系統(tǒng)|vite4+vue3+pinia前端后臺(tái)框架實(shí)例

    基于 vite4.x+vue3+pinia 前端后臺(tái)管理系統(tǒng)解決方案 ViteAdmin 。 前段時(shí)間分享了一篇vue3自研pc端UI組件庫(kù)VEPlus。這次帶來(lái)最新開(kāi)發(fā)的基于 vite4+vue3+pinia 技術(shù)棧搭配ve-plus組件庫(kù)構(gòu)建的中后臺(tái)權(quán)限管理系統(tǒng)框架。 支持vue-i18n國(guó)際化多語(yǔ)言、動(dòng)態(tài)路由鑒權(quán)、4種布局模板及tab頁(yè)面緩存 等功

    2023年04月13日
    瀏覽(27)
  • 【前端】Vue+Element UI案例:通用后臺(tái)管理系統(tǒng)-面包屑、tag欄

    【前端】Vue+Element UI案例:通用后臺(tái)管理系統(tǒng)-面包屑、tag欄

    參考視頻: VUE項(xiàng)目,VUE項(xiàng)目實(shí)戰(zhàn),vue后臺(tái)管理系統(tǒng),前端面試,前端面試項(xiàng)目 案例 鏈接 【前端】Vue+Element UI案例:通用后臺(tái)管理系統(tǒng)-導(dǎo)航欄(視頻p1-16) https://blog.csdn.net/karshey/article/details/127640658 【前端】Vue+Element UI案例:通用后臺(tái)管理系統(tǒng)-Header+導(dǎo)航欄折疊(p17-19) http

    2024年02月09日
    瀏覽(63)
  • 項(xiàng)目實(shí)戰(zhàn)-RuoYi后臺(tái)管理系統(tǒng)-登錄功能Postman接口自動(dòng)化腳本分享

    ????先來(lái)回顧一下之前寫(xiě)過(guò)的關(guān)于RuoYi后臺(tái)管理系統(tǒng)項(xiàng)目實(shí)戰(zhàn)相關(guān)的幾篇文章: 測(cè)試項(xiàng)目實(shí)戰(zhàn)----RuoYi后臺(tái)管理系統(tǒng) 項(xiàng)目實(shí)戰(zhàn)-RuoYi后臺(tái)管理系統(tǒng)-用戶(hù)管理測(cè)試點(diǎn)設(shè)計(jì) 項(xiàng)目實(shí)戰(zhàn)-RuoYi后臺(tái)管理系統(tǒng)-登錄相關(guān)接口分析 Docker搭建webdis用于提供api查詢(xún)r(jià)edis中的數(shù)據(jù) 項(xiàng)目實(shí)戰(zhàn)-RuoYi后臺(tái)管

    2023年04月20日
    瀏覽(22)
  • Vue+SpringBoot后臺(tái)管理系統(tǒng):Vue3+TypeScript項(xiàng)目搭建(一)

    Vue+SpringBoot后臺(tái)管理系統(tǒng):Vue3+TypeScript項(xiàng)目搭建(一)

    查看Note版本 查看npm版本 然后將npm升級(jí)至最新版本 將npm下載源換至http://registry.npm.taobao.org 可以在后續(xù)的npm下載提高下載速度 安裝vue cli node版本v18.16.1 vue-cli版本v5.0.8 創(chuàng)建項(xiàng)目命令 vue_typescript_elementplus_demo 是項(xiàng)目名,可以自定義 選擇 Manually select features ,進(jìn)行自定義 然后選擇

    2024年02月13日
    瀏覽(35)
  • VUE通用后臺(tái)管理系統(tǒng)(四)前端導(dǎo)出文件(CSV、XML、HTML、PDF、EXCEL)

    VUE通用后臺(tái)管理系統(tǒng)(四)前端導(dǎo)出文件(CSV、XML、HTML、PDF、EXCEL)

    常見(jiàn)的導(dǎo)出格式:CSV、XML、HTML、PDF、EXCEL 1)準(zhǔn)備工作 安裝所需相關(guān)依賴(lài) 前兩個(gè)是PDF格式需要的依賴(lài),后兩個(gè)是excel格式所需,如果沒(méi)有需求這兩種格式的可以忽略這一步 然后畫(huà)頁(yè)面 ? 頁(yè)面效果 2)導(dǎo)出CSV格式的文件 新建src/utils/utils.js文件 寫(xiě)入exportCsv方法,columns為表頭,

    2024年02月05日
    瀏覽(57)
  • 開(kāi)源項(xiàng)目學(xué)習(xí):若依RuoYi-Vue后臺(tái)管理系統(tǒng)【環(huán)境搭建】

    開(kāi)源項(xiàng)目學(xué)習(xí):若依RuoYi-Vue后臺(tái)管理系統(tǒng)【環(huán)境搭建】

    第一章 環(huán)境搭建 第二章 項(xiàng)目運(yùn)行 第三章 閱讀源碼:例子-新增用戶(hù)接口 第四章 基于ruoyi-vue開(kāi)發(fā)新項(xiàng)目 本文盡量貼近零基礎(chǔ)入門(mén),獻(xiàn)給初入門(mén)的學(xué)弟學(xué)妹們! 文章基本流程:環(huán)境配置→運(yùn)行項(xiàng)目→閱讀源碼 安裝環(huán)境時(shí)最好修改安裝路徑! Java開(kāi)發(fā)必備! JDK下載:http://www

    2023年04月19日
    瀏覽(23)
  • Vue--》Vue3打造可擴(kuò)展的項(xiàng)目管理系統(tǒng)后臺(tái)的完整指南(二)

    Vue--》Vue3打造可擴(kuò)展的項(xiàng)目管理系統(tǒng)后臺(tái)的完整指南(二)

    今天開(kāi)始使用 vue3 + ts 搭建一個(gè)項(xiàng)目管理的后臺(tái),因?yàn)槲恼聲?huì)將項(xiàng)目的每一個(gè)地方代碼的書(shū)寫(xiě)都會(huì)講解到,所以本項(xiàng)目會(huì)分成好幾篇文章進(jìn)行講解,我會(huì)在最后一篇文章中會(huì)將項(xiàng)目代碼開(kāi)源到我的 GithHub 上,大家可以自行去進(jìn)行下載運(yùn)行,希望本文章對(duì)有幫助的朋友們能多多

    2024年02月07日
    瀏覽(22)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包