主頁 > 前端設計 > Vue 電商管理系統

Vue 電商管理系統

2021-12-18 08:46:57 前端設計

1、電商管理系統

本系統前端頁面基于Vue和ElemrntUI,后端為node.js撰寫,主要應用于當下市場所流行的電商模式,通過科技的手段,使傳統的商戶交易模式變為更為高效率的電商交易模式,面向全國各地更多的客戶,

專案原始碼https://download.csdn.net/download/Zyw907155124/64631613https://download.csdn.net/download/Zyw907155124/64631613

2、專案演示

(1)登錄頁面

(2)主頁

(3)用戶管理

管理員可進入:實作模糊搜索、多條件分頁、添加用戶、編輯用戶資訊、洗掉、分配用戶角色等功能,

(4)權限管理

分為1、角色串列;2、權限串列,

角色串列:可通過樹狀結構,查看、添加、修改、洗掉不同層級的權限可訪問的選單項,

權限串列:可查詢上級選單所對應的下級選單,

(5)商品管理

分為:1、商品分類;2、商品串列;3、分類引數

商品分類:

可實作 查看、編輯不同層級的商品分類名稱以及父子級關系,

商品串列:

可實作商品的多條件搜索分頁,以及對具體商品的添加、修改和洗掉操作

本系統對于商品的添加進行了嚴格的校驗和細致的劃分,

對于商品的每一資訊都進行了嚴格的校驗,且未完成前一個步驟的情況下,無法直接跳過去進行下一個步驟的操作,

可上傳商品的圖片,

分類引數:負責查看、修改、洗掉商品分類的動態引數和靜態屬性

(6)訂單管理

可實作查看訂單的詳情、修改訂單付款狀態、修改訂單地址等功能,

(7)資料統計

通過可視化工具實作不同地區用戶的來源數量,

3、原始碼

(1)登錄頁面

<template>
    <div class="login_container">
        <img src="../assets/img/bizhi2.png" style="width: 100%;height: 850px">
        <!-- 登錄盒子  -->
        <div class="login_box">
            <!-- 頭像 -->
            <div class="avatar_box">
                <img src="../assets/img/沃爾瑪.jpg" alt="">
            </div>
            <!-- 登錄表單 -->
            <el-form :model="loginForm" ref="LoginFormRef" :rules="loginFormRules" label-width="0px" class="login_form">
                <!-- 用戶名 -->
                <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 type="password" v-model="loginForm.password" prefix-icon="iconfont icon-3702mima"></el-input>
                </el-form-item>
                <!-- 按鈕 -->
                <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 {
                //資料系結
                loginForm: {
                    username: 'admin',
                    password: '123456'
                },
                //表單驗證規則
                loginFormRules: {
                    username: [
                        { required: true, message: '請輸入登錄名', trigger: 'blur' },
                        {
                            min: 3,
                            max: 10,
                            message: '登錄名長度在 3 到 10 個字符',
                            trigger: 'blur'
                        }
                    ],
                    password: [
                        { required: true, message: '請輸入密碼', trigger: 'blur' },
                        {
                            min: 6,
                            max: 15,
                            message: '密碼長度在 6 到 15 個字符',
                            trigger: 'blur'
                        }
                    ]
                }
            }
        },
        //添加行為,
        methods: {
            //添加表單重置方法
            resetLoginForm() {
                //this=>當前組件物件,其中的屬性$refs包含了設定的表單ref
                  console.log(this)
                this.loginForm.username = '';
                this.loginForm.password = '';
                // this.$refs.LoginFormRef.resetFields()
            },
            login() {
                //點擊登錄的時候先呼叫validate方法驗證表單內容是否有誤
                this.$refs.LoginFormRef.validate(async valid => {
                    console.log(this.loginFormRules)
                    //如果valid引數為true則驗證通過
                    if (!valid) {
                        return
                    }

                    //發送請求進行登錄
                    const { data: res } = await this.$http.post('login', this.loginForm)
                    //   console.log(res);
                    if (res.meta.status !== 200) {
                        return this.$message.error('登錄失敗:' + res.meta.msg) //console.log("登錄失敗:"+res.meta.msg)
                    }

                    this.$message.success('登錄成功')
                    console.log(res)
                    //保存token
                    window.sessionStorage.setItem('token', res.data.token)
                    // 導航至/home
                    this.$router.push('/home')
                })
            }
        }
    }
</script>

<style lang="less" scoped>
    .login_container {
        background-color: #2b5b6b;
        height: 100%;
    }
    .login_box {
        width: 450px;
        height: 300px;
        background: #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>

(2)主頁

<template>
    <el-container class="home-container" >
        <!-- 頭部區域 -->
        <el-header >
            <div>
                <!-- logo -->
<!--                <a href="Home.vue"><img src="../assets/logo.png" alt=""></a>-->
                <a href="/welcome"><img src="../assets/img/jdd.jpg" alt="" style="width: 200px;height: 20%;padding-left: 0" ></a>
                <!-- 頂部標題 -->
<!--                <span>電商后臺管理系統</span>-->
                <img src="../assets/img/apple.jpg" style="width: 1350px">
            </div>
            <el-button type="info" @click="logout"> 退出 </el-button>
        </el-header>
        <!-- 頁面主體區域 -->
        <el-container>
            <!-- 側邊欄 -->
            <el-aside width="200px">
                <!-- 側邊欄選單 -->
                <el-menu
                        background-color="#333744"
                        text-color="#fff"
                        active-text-color="#ffd04b" router
                        unique-opened
                        :default-active="activePath"
                >
                    <!-- 一級選單 -->
                    <el-submenu  v-for="item in menuList" :key="item.id" :index="item.id+''">
                        <!-- 一級選單模板 -->
                        <template slot="title">
                            <!-- 圖示 -->
                            <i :class="item.psIcon"></i>
                            <!-- 文本 -->
                            <span>{{item.authName}}</span>
                        </template>
                        <!-- 二級子選單 -->
                        <el-menu-item :index="'/'+subItem.path" v-for="subItem in item.children" :key="subItem.id">
                            <!-- 二級選單模板 -->
                            <template slot="title">
                                <!-- 圖示 -->
                                <i class="el-icon-location"></i>
                                <!-- 文本 -->
                                <span>{{subItem.authName}}</span>
                            </template>
                        </el-menu-item>
                    </el-submenu>
                </el-menu>
            </el-aside>
            <!-- 主體結構 -->
            <el-main>
                <router-view></router-view>
            </el-main>
        </el-container>
    </el-container>
</template>

<script>
    export default {
        data() {
            return {
                // 左側選單資料
                menuList: null,
                // 被激活的鏈接地址
                activePath: ''
            }
        },
        created() {
            // 在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(this.menuList)
            }
        }
    }
</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>
<template>
    <el-carousel :interval="4000" type="card" height="500px" >
        <el-carousel-item v-for="item in urls" :key="item">
            <img :src="item" >
        </el-carousel-item>
    </el-carousel>
</template>

<script>
    export default {
        data() {
            return {
                urls: [
                    'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
                    'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
                    'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
                    'https://fuss10.elemecdn.com/9/bb/e27858e973f5d7d3904835f46abbdjpeg.jpeg',
                    'https://fuss10.elemecdn.com/d/e6/c4d93a3805b3ce3f323f7974e6f78jpeg.jpeg',
                    'https://fuss10.elemecdn.com/3/28/bbf893f792f03a54408b3b7a7ebf0jpeg.jpeg',
                    'https://fuss10.elemecdn.com/2/11/6535bcfb26e4c79b48ddde44f4b6fjpeg.jpeg',
                    'https://2oa-file.oss-cn-beijing.aliyuncs.com/t/2021-11-29/7954995fda494741af1e62d0f067ba68-car.jpg'
        ],
                currentDate: new Date()
            }
        }
    }
</script>

<style scoped>
    .el-carousel__item h3 {
        color: #475669;
        font-size: 14px;
        opacity: 0.75;
        line-height: 200px;
        margin: 0;
    }

    .el-carousel__item:nth-child(2n) {
        background-color: #99a9bf;
    }

    .el-carousel__item:nth-child(2n+1) {
        background-color: #d3dce6;
    }
    .time {
        font-size: 13px;
        color: #999;
    }

    .bottom {
        margin-top: 13px;
        line-height: 12px;
    }

    .button {
        padding: 0;
        float: right;
    }

    .image {
        width: 100%;
        display: block;
    }

    .clearfix:before,
    .clearfix:after {
        display: table;
        content: "";
    }

    .clearfix:after {
        clear: both
    }
</style>

(3)用戶管理

<template>
    <div>
        <!-- 面包屑導航 -->
        <el-breadcrumb separator="/">
            <el-breadcrumb-item :to="{ path: '/home' }">首頁</el-breadcrumb-item>
            <el-breadcrumb-item>用戶管理</el-breadcrumb-item>
            <el-breadcrumb-item>用戶串列</el-breadcrumb-item>
        </el-breadcrumb>
        <!-- 卡片視圖區域 -->
        <el-card>
            <!-- 搜索與添加區域 -->
            <el-row :gutter="20">
                <el-col :span="7">
                    <el-input placeholder="請輸入內容" v-model="queryInfo.query" clearable @clear="getUserList">
                        <el-button slot="append" icon="el-icon-search" @click="serch"></el-button>
                    </el-input>
                </el-col>
                <el-col :span="4">
                    <el-button type="primary" @click="add()">添加用戶</el-button>
                </el-col>
                <el-dialog :title=title :visible.sync="dialogFormVisible">
                    <el-form :model="users" ref="LoginFormRef" :rules="loginFormRules">
                        <el-form-item label="用戶名稱" prop="username">
                            <el-input v-model="users.username" autocomplete="off"></el-input>
                        </el-form-item>
                        <el-form-item label="用戶密碼" prop="password" v-if="users.id == null">
                            <el-input v-model="users.password" autocomplete="off" v-if="users.id == null"></el-input>
                        </el-form-item>
                        <el-form-item label="郵箱" prop="email">
                            <el-input v-model="users.email" autocomplete="off"></el-input>
                        </el-form-item>
                        <el-form-item label="手機號" prop="mobile">
                            <el-input v-model="users.mobile" autocomplete="off"></el-input>
                        </el-form-item>
                    </el-form>
                    <div slot="footer" class="dialog-footer">
                        <el-button @click="dialogFormVisible = false">取 消</el-button>
                        <el-button type="primary" @click="update(users.id)">確 定</el-button>
                    </div>
                </el-dialog>
            </el-row>
        </el-card>
        <!-- 用戶串列區域 -->
        <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="電話" prop="mobile"></el-table-column>
            <el-table-column label="角色" prop="role_name"></el-table-column>
            <el-table-column label="狀態">
                <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-dialog :title="title" :visible.sync="duoxuan">
                        <el-select v-model="rid" autocomplete="off">
                            <el-option
                                    v-for="role in rolelist"
                                    :key="role.id"
                                    :label="role.roleName"
                                    :value="role.id">
                            </el-option>
                        </el-select>
                            <el-button type="primary" @click="setR(rid)">確 定</el-button>
                        </el-dialog>
                    </template>
                </template>
            </el-table-column>
        </el-table>
        <!-- 分頁導航區域
@size-change(pagesize改變時觸發)
@current-change(頁碼發生改變時觸發)
:current-page(設定當前頁碼)
:page-size(設定每頁的資料條數)
:total(設定總頁數) -->
        <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>
    </div>
</template>

<script>
    export default {
        data () {
            return {
                // 獲取查詢用戶資訊的引數
                title:'',
                sea:false,
                duoxuan:false,
                users: {
                    id: '',
                    username: '',
                    password: '',
                    email: '',
                    mobile: ''
                },
                rid:'',
                rolelist:[],
                visible: false,
                formLabelWidth: '120px',
                dialogFormVisible: false,
                form2:{
                    email:'',mobile:''
                },
                queryInfo: {
                    query: '',
                    pagenum: 1,
                    pagesize: 2
                },
                //表單驗證規則
                loginFormRules: {
                    username: [
                        {required: true, message: '請輸入登錄名', trigger: 'blur'},
                        {
                            min: 3,
                            max: 10,
                            message: '登錄名長度在 3 到 10 個字符',
                            trigger: 'blur'
                        }
                    ],
                    password: [
                        {required: true, message: '請輸入密碼', trigger: 'blur'},
                        {
                            min: 6,
                            max: 15,
                            message: '密碼長度在 6 到 15 個字符',
                            trigger: 'blur'
                        }
                    ],
                    email: [
                        // {required: true, message: '請輸入郵箱', triggger: 'blur'},
                        {
                            pattern: /^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/,
                            message: "正確的郵箱格式為xxx@xx.com",
                            trigger: 'blur'
                        }
                    ],
                    mobile: [
                        // {required: true, message: "請輸入手機號碼", trigger: "blur"},
                        {
                            pattern: /^1[356789]\d{9}$/,
                            message: "請填寫11位正確的手機號碼",
                            trigger: "blur"
                        }]
                },
                // 保存請求回來的用戶串列資料
                userlist: [],
                total: 0,
                options: [{}],
                value: ''
            }
        },
        created () {
            this.getUserList()
        },
        methods: {
            serch(){
                if (this.queryInfo.query.trim()!=""){
                    this.sea = true;
                }
                this.queryInfo.pagenum = 1;
                this.getUserList();
            },
            async getUserList() {
                const { data: res } = await this.$http.get('users', {
                    params: this.queryInfo
                })
                if (res.meta.status !== 200) {
                    return this.$message.error('獲取用戶串列失敗!')
                }
                this.userlist = res.data.users
                this.total = res.data.total
                console.log(res)
            },
            async setRole(row){
                this.duoxuan = true;
                this.id = row.id;
                this.rid = row.roleId;
                const { data: res } = await this.$http.get('roles/')
                if (res.meta.status !== 200) {
                    return this.$message.error('獲取角色串列失敗!')
                }
                this.rolelist = res.data;
            },
            setR(rid){
                console.log("rid="+rid);
                console.log("this.id="+this.id);
                console.log("users/:"+this.id+"/"+rid);
                this.$http.put("users/"+this.id+"/"+rid);
                this.getUserList();
                this.id = '';
                this.duoxuan = false;
            },
            handleSizeChange(newSize) {
                //pagesize改變時觸發,當pagesize發生改變的時候,我們應該
                //以最新的pagesize來請求資料并展示資料
                //   console.log(newSize)
                // this.search?this.queryInfo.pagesize=1:this.queryInfo.pagesize = newSize;
                this.queryInfo.pagesize = newSize;
               //重新按照pagesize發送請求,請求最新的資料
                this.getUserList();
            },
            handleCurrentChange( current ) {
                //頁碼發生改變時觸發當current發生改變的時候,我們應該
                //以最新的current頁碼來請求資料并展示資料
                //   console.log(current)
                if (!this.search){
                    this.queryInfo.pagenum = current;
                }
                //重新按照pagenum發送請求,請求最新的資料
                this.getUserList();
            },
            async userStateChanged(row) {
                //發送請求進行狀態修改
                const { data: res } = await this.$http.put(
                    `users/${row.id}/state/${row.mg_state}`
                )
                //如果回傳狀態為例外狀態則報錯并回傳
                if (res.meta.status !== 200) {
                    row.mg_state = !row.mg_state
                    return this.$message.error('修改狀態失敗')
                }
                this.$message.success('更新狀態成功')
            },
            //添加
            add() {
                this.users = {};
                this.title = "添加";
                this.dialogFormVisible = true;
            },
            // 修改
            async showEditDialog(id) {
                //找出需要修改的資料的資訊
                const {data: res} = await this.$http.get("users/" + id);
                if (res.meta.status !== 200) {
                    return this.$message.error('查詢失敗')
                }
                this.$message.success('查詢成功');
                this.users = res.data;
                console.log(this.users);
                this.title = "修改";
                this.dialogFormVisible = true;
            },
            //添加/修改
            async update(id) {
                this.$refs.LoginFormRef.validate(async valid => {
                    console.log(this.loginFormRules);
                    //如果valid引數為true則驗證通過
                    if (!valid) {
                        return
                    }
                    if (id != null) {
                        const {data: res} = await this.$http.put(`users/${id}`, this.users);
                        if (res.meta.status !== 200) {
                            return this.$message.error('修改失敗')
                        }
                        this.$message.success('修改成功');
                    } else {
                        const {data: res} = await this.$http.post("users", this.users);
                        if (res.meta.status !== 201) {
                            return this.$message.error('添加失敗')
                        } else {
                            this.$message.success('添加成功');
                        }
                    }
                    this.users = '';
                    this.dialogFormVisible = false;
                    this.getUserList()
                })
            },
            removeUserById(id){
                this.$confirm('此操作將永久洗掉該檔案, 是否繼續?', '提示', {
                    confirmButtonText: '確定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    this.$http.delete("users/"+id).then(() => {
                        this.queryInfo.pagenum = this.userlist.length === 1 ? this.queryInfo.pagenum - 1 : this.queryInfo.pagenum;
                        this.queryInfo.pagenum = this.queryInfo.pagenum < 1 ? 1 : this.queryInfo.pagenum;
                        this.getUserList();
                    }),
                        this.$message({
                            type: 'success',
                            message: '洗掉成功!'
                        });
                }).catch(() => {
                    this.$message({
                        type: 'info',
                        message: '已取消洗掉'
                    });
                });
            },
            //獲取角色串列

        }
    }
</script>

<style scoped>

</style>

(4)權限管理

1、角色串列;

<template>
    <div>
        <!-- 面包屑導航區域 -->
        <el-breadcrumb separator-class="el-icon-arrow-right">
            <el-breadcrumb-item :to="{ path: '/home' }">首頁</el-breadcrumb-item>
            <el-breadcrumb-item>權限管理</el-breadcrumb-item>
            <el-breadcrumb-item>角色串列</el-breadcrumb-item>
        </el-breadcrumb>

        <!-- 卡片視圖 -->
        <el-card>
            <!-- 添加角色按鈕區域 -->
            <el-row>
                <el-col>
                    <el-button type="primary" @click="res()">添加角色</el-button>
                    <el-dialog :visible.sync="dialogFormVisible">
                        <el-form :model="role1" >
                            <el-form-item label="角色名稱" prop="roleName">
                                <el-input v-model="role1.roleName" autocomplete="off"></el-input>
                            </el-form-item>
                            <el-form-item label="角色描述" prop="roleDesc">
                                <el-input v-model="role1.roleDesc" autocomplete="off"></el-input>
                            </el-form-item>
                        </el-form>
                        <div slot="footer" class="dialog-footer">
                            <el-button @click="dialogFormVisible = false">取 消</el-button>
                            <el-button type="primary" @click="insert()">確 定</el-button>
                        </div>
                    </el-dialog>
                </el-col>
            </el-row>

            <!-- 角色串列區域 -->
            <el-table :data="roleList" border stripe>
                <!-- 展開列 -->
                <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">
                            <!-- 渲染一級權限 -->
                            <el-col :span="5">
                                <el-tag closable >{{item1.authName}}</el-tag>
                                <i class="el-icon-caret-right" @close="removeRightById(scope.row, item1.id)"></i>
                            </el-col>
                            <!-- 渲染二級和三級權限 -->
                            <el-col :span="19">
                                <!-- 通過 for 回圈 嵌套渲染二級權限 -->
                                <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>{{item2.authName}}</el-tag>
                                        <i class="el-icon-caret-right" @close="removeRightById(scope.row, item2.id)"></i>
                                    </el-col>
                                    <el-col :span="18">
                                        <el-tag closable type="warning" v-for="item3 in item2.children" :key="item3.id">{{item3.authName}}</el-tag>
                                        <i class="el-icon-caret-right" @close="removeRightById(scope.row, item3.id)"></i>
                                    </el-col>
                                </el-row>
                            </el-col>
                        </el-row>
                    </template>
                </el-table-column>
                <el-table-column label="角色名稱" 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" @click="selectById(scope.row.id)" >編輯</el-button>
                        <el-dialog :visible.sync="dialogFormVisible2">
                            <el-form :model="role" ref="LoginFormRef">
                                <el-form-item label="角色名稱" prop="roleName">
                                    <el-input v-model="role.roleName" autocomplete="off"></el-input>
                                </el-form-item>
                                <el-form-item label="角色描述" prop="roleDesc">
                                    <el-input v-model="role.roleDesc" autocomplete="off"></el-input>
                                </el-form-item>
                            </el-form>
                            <div slot="footer" class="dialog-footer">
                                <el-button @click="dialogFormVisible2 = false">取 消</el-button>
                                <el-button type="primary" @click="upda(scope.row.id)">確 定</el-button>
                            </div>
                        </el-dialog>
                        <el-button size="mini" type="danger" icon="el-icon-delete" @click="delRole(scope.row.id)">洗掉</el-button>
                        <el-button size="mini" type="warning" icon="el-icon-setting" @click="showSetRightDialog(scope.row)">分配權限</el-button>
                        <!-- 分配權限對話框 -->
                        <el-dialog title="分配權限" :visible.sync="setRightDialogVisible" width="50%" @close="setRightDialogClose">
                            <!-- 樹形組件
                            show-checkbox:顯示復選框
                            node-key:設定選中節點對應的值
                            default-expand-all:是否默認展開所有節點
                            :default-checked-keys 設定默認選中項的陣列
                            ref:設定參考 -->
                            <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>
                    </template>
                </el-table-column>
            </el-table>
        </el-card>
    </div>
</template>


<script>
    export default {
        data() {
            return {
                // 角色串列資料
                roleList: [],
                // 控制分配權限對話框的顯示
                setRightDialogVisible: false,
                // 權限樹資料
                rightsList: [],
                // 樹形控制元件的屬性系結物件
                treeProps: {
                    // 通過label設定樹形節點文本展示authName
                    label: 'authName',
                    // 設定通過children屬性展示子節點資訊
                    children: 'children'
                },
                // 設定樹形控制元件中默認選中的內容
                defKeys: [],
                // 保存正在操作的角色id
                roleId: '',
                role1:{
                    roleName:'',roleDesc:''
                },
                role:{
                    id:'',roleName:'',roleDesc:''
                },
                dialogFormVisible:false,
                dialogFormVisible2:false
            }
        },
        created() {
            this.getRoleList()
        },
        methods: {
            async getRoleList() {
                const { data: res } = await this.$http.get('roles')
                // 如果回傳狀態為例外狀態則報錯并回傳
                if (res.meta.status !== 200) { return this.$message.error('獲取角色串列失敗') }
                // 如果回傳狀態正常,將請求的資料保存在data中
                // this.roleList = res.data
                console.log(res.data)
                this.roleList = res.data
            },
            async removeRightById(role, rightId) {
                // 彈窗提示用戶是否要洗掉
                const confirmResult = await this.$messagebox.confirm(
                    '請問是否要洗掉該權限',
                    '洗掉提示',
                    {
                        confirmButtonText: '確認洗掉',
                        cancelButtonText: '取消',
                        type: 'warning'
                    }
                ).catch(err => err)
                // 如果用戶點擊確認,則confirmResult 為'confirm'
                // 如果用戶點擊取消, 則confirmResult獲取的就是catch的錯誤訊息'cancel'
                if (confirmResult !== 'confirm') {
                    return this.$message.info('已經取消洗掉')
                }

                // 用戶點擊了確定表示真的要洗掉
                // 當發送delete請求之后,回傳的資料就是最新的角色權限資訊
                const { data: res } = await this.$http.delete(
                    `roles/${role.id}/rights/${rightId}`
                )
                if (res.meta.status !== 200) { return this.$message.error('洗掉角色權限失敗') }

                // 無需再重新加載所有權限
                // 只需要對現有的角色權限進行更新即可
                role.children = res.data
                // this.getRoleList();
            },
            async showSetRightDialog(role) {
                // 將role.id保存起來以供保存權限時使用
                this.roleId = role.id
                // 獲取所有權限的資料
                const { data: res } = await this.$http.get('rights/tree')
                // 如果回傳狀態為例外狀態則報錯并回傳
                if (res.meta.status !== 200) return this.$message.error('獲取權限樹失敗')
                // 如果回傳狀態正常,將請求的資料保存在data中
                this.rightsList = res.data

                // 呼叫getLeafKeys進行遞回,將三級權限添加到陣列中
                this.getLeafKeys(role, this.defKeys)
                // 當點擊分配權限按鈕時,展示對應的對話框
                this.setRightDialogVisible = true
                console.log(this.defKeys)
            },
            getLeafKeys(node, arr) {
                // 該函式會獲取到當前角色的所有三級權限id并添加到defKeys中
                // 如果當前節點不包含children屬性,則表示node為三級權限
                if (!node.children) {
                    return arr.push(node.id)
                }
                // 遞回呼叫
                node.children.forEach(item => this.getLeafKeys(item, arr))
            },
            setRightDialogClose() {
                // 當用戶關閉樹形權限對話框的時候,清除掉所有選中狀態
                this.defKeys = []
            },
            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('分配權限失敗') }

                this.$message.success('分配權限成功')
                this.getRoleList()
                // 關閉對話框
                this.setRightDialogVisible = false
            },
            res(){
                this.role1 = {};
                this.dialogFormVisible = true;
            },
            //新增
            async insert(){
                    //新增
                    console.log("新增");
                    const {data: res} = await this.$http.post(`roles`, this.role1);
                    if (res.meta.status !== 201) {
                        return this.$message.error('添加失敗')
                    } else {
                        this.$message.success('添加成功');
                    }
                this.role1 = '';
                this.dialogFormVisible = false;
                this.getRoleList();
            },

            async selectById(id){
                const {data: res} = await this.$http.get(`roles/`+id, this.role);
                if (res.meta.status !== 200) {
                    return this.$message.error('查詢失敗')
                }
                this.$message.success('查詢成功');
                this.role.id = res.data.id;
                this.role.roleName = res.data.roleName;
                this.role.roleDesc = res.data.roleDesc;
                console.log(this.role);
                this.dialogFormVisible2 = true;
            },
            //修改
            async upda(id){
                console.log("id="+id);
                const {data: res} = await this.$http.put(`roles/${id}`,this.role);
                if (res.meta.status !== 200) {
                    return this.$message.error('修改失敗')
                } else {
                    this.$message.success('修改成功');
                }
                this.role = {};
                this.dialogFormVisible2 = false;
                this.getRoleList();
            },
            delRole(id){
                this.$confirm('此操作將永久洗掉該檔案, 是否繼續?', '提示', {
                    confirmButtonText: '確定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    console.log("id="+id);
                    this.$http.delete(`roles/${id}`).then(() => {
                        this.getRoleList();
                    })
                }),this.$message({
                    type: 'success',
                    message: '洗掉成功!'
                }).catch(() => {
        this.$message({
            type: 'info',
            message: '已取消洗掉'
        });
    });
            }
        }
    }
</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>

2、權限串列,

<template>
    <div>
        <!-- 面包屑導航區域 -->
        <el-breadcrumb separator-class="el-icon-arrow-right">
            <el-breadcrumb-item :to="{ path: '/home' }">首頁</el-breadcrumb-item>
            <el-breadcrumb-item>權限管理</el-breadcrumb-item>
            <el-breadcrumb-item>權限串列</el-breadcrumb-item>
        </el-breadcrumb>
        <!-- 卡片視圖 -->
        <el-card>
<!--            <tree-table :data="quanxianList" :columns="columns" :selection-type="false"-->
<!--                                              :expand-type="false" show-index index-text="#" :show-row-hover="false">-->
<!--                <template slot="level" scope="scope">-->
<!--                    <el-tag type="primary" effect="plain" size="mini" v-if="scope.row.children!=null && scope.row.pid==0">一級</el-tag>-->
<!--                    <el-tag type="success" effect="plain" size="mini" v-else-if="scope.row.children!=null && scope.row.pid!=0">二級</el-tag>-->
<!--                    <el-tag type="warning" effect="plain" size="mini" v-else>三級</el-tag>-->
<!--                </template>-->
<!--            </tree-table>-->
<!--             角色串列區域-->
            <el-table :data="quanxianList" border stripe>
                <!-- 展開列 -->
                <el-table-column type="expand">
<!--                    <el-table-column label="" prop="authName"></el-table-column>-->

                    <template slot-scope="scope">
                        <el-row :class="['bdbottom', i1 === 0 ? 'bdtop' : '', 'vcenter']" v-for="(item1, i1) in scope.row.children" :key="item1.id">
                        <!-- 渲染一級權限 -->
                            <el-col :span="5">
                                <el-tag >{{item1.authName}}</el-tag>
                                <i class="el-icon-caret-right"></i>
                            </el-col>
                            <!-- 渲染二級和三級權限 -->
                            <el-col :span="19">
                                <!-- 通過 for 回圈 嵌套渲染二級權限 -->
                                <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" >{{item2.authName}}</el-tag>
                                        <i class="el-icon-caret-right"></i>
                                    </el-col>
                                    <el-col :span="18">
                                        <el-row :class="[i2 === 0 ? '' : 'bdtop', 'vcenter']" v-for="(item3, i2) in item1.children" :key="item3.id">
                                            <el-tag  type="warning">
                                                {{item3.authName}}
                                            </el-tag>
                                            <i class="el-icon-caret-right"></i>
                                        </el-row>
                                    </el-col>
                                </el-row>
                            </el-col>
                        </el-row>
                    </template>
                </el-table-column>
                <!-- 角色串列區域 -->
                    <!-- 添加展開列 -->
<!--                    <el-table-column label="權限ID" prop="id"></el-table-column>-->
                    <el-table-column label="權限說明" prop="authName"></el-table-column>
                    <el-table-column label="權限層級" prop="level"></el-table-column>
                    <el-table-column label="權限父ID" prop="pid"></el-table-column>
                    <el-table-column label="對應訪問路徑" prop="path"></el-table-column>
            </el-table>


        </el-card>
    </div>
</template>


<script>
    export default {
        data () {
            return {
                // quanxianList: [],
                quanxianList: {
                    // 通過label設定樹形節點文本展示authName
                    label: 'authName',
                    // 設定通過children屬性展示子節點資訊
                    children: 'children'
                },
                menus:{
                    id:'',authName:'',path:'',children:''
                }
            }
        },
        created () {
            this.getRoleList()
        },
        methods: {
            async getRoleList () {
                const { data: res } = await this.$http.get('rights/tree')
                // 如果回傳狀態為例外狀態則報錯并回傳
                if (res.meta.status !== 200) {
                    return this.$message.error('獲取角色串列失敗')
                }
                console.log(res.data)
                // 如果回傳狀態正常,將請求的資料保存在data中
                this.quanxianList = res.data
            },
            async getLeftList () {
                const { data: res } = await this.$http.get('menus')
                // 如果回傳狀態為例外狀態則報錯并回傳
                if (res.meta.status !== 200) {
                    return this.$message.error('獲取選單串列失敗')
                }
                console.log(res.data)
                // 如果回傳狀態正常,將請求的資料保存在data中
                this.menus = res.data
            }
        }
    }
</script>

(5)商品管理

1、商品分類;

<template>
    <div>
        <!-- 面包屑導航 -->
        <el-breadcrumb separator="/">
            <el-breadcrumb-item :to="{ path: '/home' }">首頁</el-breadcrumb-item>
            <el-breadcrumb-item>商品管理</el-breadcrumb-item>
            <el-breadcrumb-item>商品分類</el-breadcrumb-item>
        </el-breadcrumb>
        <!-- 卡片視圖區域 -->
        <el-card>
            <!-- 添加分類按鈕區域 -->
            <el-row>
                <el-col>
                    <el-button type="primary" @click="showAddCateDialog">添加分類</el-button>
                </el-col>
            </el-row>
            <!-- 添加分類對話框 -->
            <el-dialog title="添加分類" :visible.sync="addCateDialogVisible" width="50%"  @close="addCateDialogClosed">
                <!-- 添加分類表單 -->
                <el-form :model="addCateForm" :rules="addCateFormRules" ref="addCateFormRef" label-width="100px">
                    <el-form-item label="分類名稱" prop="cat_name">
                        <el-input v-model="addCateForm.cat_name"></el-input>
                    </el-form-item>
                                        <el-form-item label="父級分類" prop="cat_pid" v-if="this.pid==''">
                                            <!-- expandTrigger='hover'(滑鼠懸停觸發級聯) v-model(設定級聯選單系結資料) :options(指定級聯選單資料源)  :props(用來配置資料顯示的規則)
                                            clearable(提供“X”號完成洗掉文本功能) change-on-select(是否可以選中任意一級的選單) -->
                                            <el-cascader expandTrigger='hover' v-model="selectedKeys" :options="parentCateList" :props="cascaderProps" @change="parentCateChange" clearable change-on-select></el-cascader>
                                        </el-form-item>
                </el-form>
                <span slot="footer" class="dialog-footer">
    <el-button @click="res">取 消</el-button>
    <el-button type="primary" @click="addCate">確 定</el-button>
  </span>
            </el-dialog>
            <!-- 分類表格  -->
            <!-- 分類表格
            :data(設定資料源) :columns(設定表格中列配置資訊) :selection-type(是否有復選框)
            :expand-type(是否展開資料) show-index(是否設定索引列) index-text(設定索引列頭)
            border(是否添加縱向邊框) :show-row-hover(是否滑鼠懸停高亮) -->
            <tree-table :data="cateList" :columns="columns" :selection-type="false"
                        :expand-type="false" show-index index-text="#" border :show-row-hover="false">
                <!-- 排序 -->
                <template slot="order" slot-scope="scope">
                    <el-tag size="mini" v-if="scope.row.cat_level===0">一級</el-tag>
                    <el-tag size="mini" type="success" v-else-if="scope.row.cat_level===1">二級</el-tag>
                    <el-tag size="mini" type="warning" v-else>三級</el-tag>
                </template>
                <!-- 操作 -->
                <template slot="opt" slot-scope="scope">
                    <el-button size="mini" type="primary" icon="el-icon-edit" @click="bj(scope.row.cat_id)">編輯</el-button>
                    <el-button size="mini" type="danger" icon="el-icon-delete" @click="del(scope.row.cat_id)">洗掉</el-button>
                </template>
            </tree-table>
            <!-- 分頁 -->
            <!-- 分頁 -->
            <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="queryInfo.pagenum" :page-sizes="[3, 5, 10, 15]" :page-size="queryInfo.pagesize" layout="total, sizes, prev, pager, next, jumper" :total="total">
            </el-pagination>
        </el-card>
    </div>
</template>

<script>
    export default {
        data() {
            return {
                // 商品分類資料串列
                cateList: [],
                columns: [
                    {label:'分類名稱',prop:'cat_name'},
                    {label:'排序',prop:'',type:'template',template:'order'},
                    {label:'操作',prop:'',type:'template',template:'opt'}
                ],
                // 查詢分類資料的條件
                queryInfo: {
                    type: 3,
                    pagenum: 1,
                    pagesize: 5
                },
                pid:'',
                // 保存總資料條數
                total: 0,
                //用來顯示或隱藏添加分類對話框
                addCateDialogVisible: false,
                dialogFormVisible2: false,
//添加分類的表單資料物件
                addCateForm:{
                    //分類名稱
                    cat_name:'',
                    //添加分類的父級id,0則表示父級為0.添加一級分類
                    cat_pid:0,
                    //添加分類的等級,0則表示添加一級分類
                    cat_level:0
                },
//保存1,2級父級分類的串列
                parentCateList:[],
//添加分類校驗規則
                addCateFormRules:{
                    //驗證規則
                    cat_name:[ {required:true , message:'請輸入分類名稱',trigger:'blur'} ]
                },
                //配置級聯選單中資料如何展示
                cascaderProps:{
                    value:'cat_id',
                    label:'cat_name',
                    children:'children',
                    expandTrigger:'hover'
                },
//系結用戶選擇的分類值
                selectedKeys:[]
            }
        },
        created() {
            this.getCateList()
        },
        methods: {
            async getCateList() {
                // 獲取商品分類資料
                const { data: res } = await this.$http.get('categories', {
                    params: this.queryInfo
                })

                if (res.meta.status !== 200) {
                    return this.$message.error('獲取商品串列資料失敗')
                }
                // 將資料串列賦值給cateList
                this.cateList = res.data.result
                // 保存總資料條數
                this.total = res.data.total
                //   console.log(res.data);
            },
                handleSizeChange(newSize){
                    //當pagesize發生改變時觸發
                    this.queryInfo.pagesize = newSize;
                    this.getCateList();
                },
                handleCurrentChange(newPage){
                    //當pagenum發生改變時觸發
                    this.queryInfo.pagenum = newPage;
                    this.getCateList();
                },
            showAddCateDialog() {
                //呼叫getParentCateList獲取分類串列
                this.getParentCateList()
                //顯示添加分類對話框
                this.addCateDialogVisible = true;
            },
            res(){
                this.addCateForm.cat_name = '';
                this.addCateDialogVisible = false;
                this.pid = '';
            },
            async getParentCateList(){
                //獲取父級分類資料串列
                const { data: res } = await this.$http.get('categories', {
                    params: {type:2}
                })
                if (res.meta.status !== 200) {
                    return this.$message.error('獲取商品分類串列資料失敗')
                }
                this.parentCateList = res.data
            },
            parentCateChange(){
                //級聯選單中選擇項發生變化時觸發
                console.log(this.selectedKeys)
                //如果用戶選擇了父級分類
                if(this.selectedKeys.length > 0){
                    //則將陣列中的最后一項設定為父級分類
                    this.addCateForm.cat_pid = this.selectedKeys[this.selectedKeys.length - 1]
                    //level也要跟著發生變化
                    this.addCateForm.cat_level = this.selectedKeys.length
                    return
                }else{
                    this.addCateForm.cat_pid = 0
                    this.addCateForm.cat_level = 0
                    return
                }
            },
            addCateDialogClosed(){
                //當關閉添加分類對話框時,重置表單
                //this.$refs.addCateFormRef.resetFields()
                this.selectedKeys = [];
                this.addCateForm.cat_pid = 0
                this.addCateForm.cat_level = 0
            },
            async addCate() {
                console.log('pid='+this.pid);
                if (this.pid==''){
                    console.log('添加');
                    //點擊確定,完成添加分類
                    console.log('cat_name='+this.addCateForm.cat_name)
                    console.log('cat_pid='+this.addCateForm.cat_pid)
                    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('添加分類失敗')
                        }
                        this.$message.success('添加分類成功')
                        this.getCateList()
                        this.addCateDialogVisible = false;
                        this.addCateForm = {};
                    });
                }else {
                    //編輯
                    console.log('編輯');

                    const {data: res} = await this.$http.put('categories/'+this.pid, this.addCateForm);
                    if (res.meta.status !== 200) {
                        return this.$message.error('編輯分類失敗')
                    }else {
                        this.$message.success('編輯分類成功')
                    }
                    this.getCateList();
                    this.addCateDialogVisible = false;
                    this.addCateForm = {};
                    this.pid = '';
                }

            },
            async bj(id){
              this.pid = id;
              console.log("id="+id);
                this.addCateDialogVisible= true;
                const {data: res} = await this.$http.get('categories/'+this.pid);
                this.addCateForm = res.data;
            },
            del(id){
                this.$confirm('此操作將永久洗掉該檔案, 是否繼續?', '提示', {
                    confirmButtonText: '確定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    console.log("id="+id);
                    this.$http.delete("categories/"+id).then(() => {
                        this.queryInfo.pagenum = this.cateList.length === 1 ? this.queryInfo.pagenum - 1 : this.queryInfo.pagenum;
                        this.queryInfo.pagenum = this.queryInfo.pagenum < 1 ? 1 : this.queryInfo.pagenum;
                        this.getCateList();
                    }),
                        this.$message({
                            type: 'success',
                            message: '洗掉成功!'
                        });
                }).catch(() => {
                    this.$message({
                        type: 'info',
                        message: '已取消洗掉'
                    });
                });
            },
            }
    }
</script>

<style scoped>

</style>

2、商品串列;

<template>
    <div>
        <!-- 面包屑導航 -->
        <el-breadcrumb separator="/">
            <el-breadcrumb-item :to="{ path: '/home' }">首頁</el-breadcrumb-item>
            <el-breadcrumb-item>商品管理</el-breadcrumb-item>
            <el-breadcrumb-item>商品串列</el-breadcrumb-item>
        </el-breadcrumb>
        <!-- 卡片視圖區域 -->
        <el-card>
            <!-- 搜索欄 -->
            <el-row :gutter="20">
                <el-col :span="8">
                    <el-input placeholder="請輸入內容" v-model="queryInfo.query" clearable>
                        <el-button slot="append" icon="el-icon-search" @click="sea()"/>
                    </el-input>
                </el-col>
                <el-col :span="4">
                    <el-button type="primary" @click="goAddPage">添加商品</el-button>
                </el-col>
            </el-row>

            <!-- 表格區域 -->
            <el-table :data="goodsList" border stripe>
                <el-table-column type="index"/>
                <el-table-column label="商品名稱" prop="goods_name"/>
                <el-table-column label="商品價格(元)" prop="goods_price" width="95px"/>
                <el-table-column label="商品重量" prop="goods_weight" width="95px"/>
                <el-table-column label="創建時間" prop="add_time" width="140px">
                    <template slot-scope="scope">
                        {{scope.row.add_time | dateFormat}}
                    </template>
                </el-table-column>
                <el-table-column label="操作" width="125px">
                    <template slot-scope="scope">
                        <el-button size="mini" type="primary" icon="el-icon-edit" @click="update(scope.row.goods_id)"/>
                        <el-button size="mini" type="danger" icon="el-icon-delete" @click="del(scope.row.goods_id)"/>
                    </template>
                </el-table-column>
            </el-table>

            <!-- 分頁 -->
            <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange"
                           :current-page="queryInfo.pagenum" :page-sizes="[3, 5, 10, 15]"
                           :page-size="queryInfo.pagesize" layout="total, sizes, prev, pager, next, jumper"
                           :total="total">
            </el-pagination>
            <el-dialog title="修改商品" :visible.sync="dialogFormVisible" width="60%">
                <el-scrollbar style="height: 400px">
                    <el-form :model="good" ref="updateGoodsForm">
                        <el-form-item label="商品名稱" :label-width="formLabelWidth" prop="goods_name">
                            <el-input v-model="good.goods_name" autocomplete="off"></el-input>
                        </el-form-item>
                        <el-form-item label="商品價格" :label-width="formLabelWidth" prop="goods_price">
                            <el-input v-model="good.goods_price" autocomplete="off"></el-input>
                        </el-form-item>
                        <el-form-item label="商品重量" :label-width="formLabelWidth" prop="goods_weight">
                            <el-input v-model="good.goods_weight" autocomplete="off"></el-input>
                        </el-form-item>
                        <el-form-item label="商品數量" :label-width="formLabelWidth" prop="goods_number">
                            <el-input v-model="good.goods_number" autocomplete="off"></el-input>
                        </el-form-item>
                        <el-form-item label="商品介紹" :label-width="formLabelWidth" prop="goods_introduce">
                            <quill-editor v-model="good.goods_introduce" autocomplete="off"></quill-editor>
                        </el-form-item>
                    </el-form>
                </el-scrollbar>
                <div slot="footer" class="dialog-footer">
                    <el-button @click="dialogFormVisible = false">取 消</el-button>
                    <el-button type="primary" @click="updateGood()">確 定</el-button>
                </div>
            </el-dialog>
        </el-card>
    </div>
</template>

<script>
    export default {
        name: "goods",
        data() {
            return {
                dialogFormVisible: false,
                formLabelWidth: '120px',
                sear: false,
                good: {

                },
                //查詢引數
                queryInfo: {
                    query: '',
                    pagenum: 1,
                    pagesize: 10
                },
                //保存商品串列資訊
                goodsList: [],
                //總資料條數
                total: 0,
            }
        },
        created() {
            this.getGoodsList()
        },
        methods: {
            sea() {
                if (this.queryInfo.query.trim() !== '') {
                    this.sear = true;
                }
                this.queryInfo.pagenum = 1;
                this.getGoodsList();
            },
            async getGoodsList() {
                //   根據分頁獲取對應的商品串列
                const {data: res} = await this.$http.get('goods', {
                    params: this.queryInfo
                });

                if (res.meta.status !== 200) {
                    return this.$message.error('獲取商品串列失敗')
                }
                console.log(res.data);
                this.$message.success('獲取商品串列成功');
                this.goodsList = res.data.goods;
                this.total = res.data.total
            },
            handleSizeChange(newSize) {
                //當頁號發生改變時,更改pagesize,重新請求
                this.queryInfo.pagesize = newSize;
                this.getGoodsList();
            },
            handleCurrentChange(newPage) {
                //當頁碼發生改變時,更改pagesize,重新請求
                if (!this.sear) {
                    this.queryInfo.query = '';
                }
                this.queryInfo.pagenum = newPage;
                this.getGoodsList();
            },
            goAddPage() {
                this.$router.push('/goods/add')
            },
            async update(id) {
                const {data: res} = await this.$http.get("goods/" + id);
                if (res.meta.status !== 200) {
                    return this.$message.error('查詢商品失敗')
                }
                this.$message.success('查詢商品成功');
                this.good = res.data;
                console.log(this.good);
                this.dialogFormVisible = true;
            },
            async updateGood() {
                const {data: res} = await this.$http.put(`goods/${this.good.goods_id}`, this.good);
                console.log(res);
                if (res.meta.status !== 200) {
                    return this.$message.error('修改商品失敗')
                }
                this.$message.success('修改商品成功');
                // 關閉對話框
                this.dialogFormVisible = false;
                this.getGoodsList()
            },
            async del(id) {
                const {data: res} = await this.$http.delete(`goods/${id}`);
                if (res.meta.status !== 200) {
                    return this.$message.error('洗掉商品失敗')
                }
                this.$message.success('洗掉商品成功');
                this.getGoodsList();
            }

        }

    }
</script>

<style scoped>

</style>

添加商品

<template>
    <div>
        <h3>添加商品</h3>
        <!-- 面包屑導航 -->
        <el-breadcrumb separator="/">
            <el-breadcrumb-item :to="{ path: '/home' }">首頁</el-breadcrumb-item>
            <el-breadcrumb-item>商品管理</el-breadcrumb-item>
            <el-breadcrumb-item>添加商品</el-breadcrumb-item>
        </el-breadcrumb>
        <!-- 卡片視圖區域 -->
        <el-card>
            <!-- 訊息提示 -->
            <el-alert title="添加商品資訊" type="info" center show-icon :closable="false">
            </el-alert>

            <!-- 步驟條組件 -->
            <!-- align-center(居中效果) -->
            <el-steps :space="200" :active="activeIndex - 0" finish-status="success" align-center>
                <el-step title="基本資訊"></el-step>
                <el-step title="商品引數"></el-step>
                <el-step title="商品屬性"></el-step>
                <el-step title="商品圖片"></el-step>
                <el-step title="商品內容"></el-step>
                <el-step title="完成"></el-step>
            </el-steps>

            <!-- tab欄區域:el-tab-pane必須是el-tabs的子節點
            :tab-position="'left'"(設定tab欄為左右結構tab欄) -->
            <!-- 表單:label-position="top"(設定label在文本框上方) -->
            <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="商品名稱" prop="goods_name">
                            <el-input v-model="addForm.goods_name"></el-input>
                        </el-form-item>
                        <el-form-item label="商品價格" 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="商品數量" prop="goods_number">
                            <el-input v-model="addForm.goods_number" type="number"></el-input>
                        </el-form-item>
                        <el-form-item label="商品分類" prop="goods_cat">
                            <!-- 選擇商品分類的級聯選擇框 -->
                            <el-cascader expandTrigger='hover' v-model="addForm.goods_cat" :options="cateList" :props="cateProps" @change="handleChange" clearable></el-cascader>
                        </el-form-item>
                    </el-tab-pane>
                    <el-tab-pane label="商品引數" name="1">
                        <!-- 渲染表單item項 -->
                        <el-form-item :label="item.attr_name" :key="item.attr_id" v-for="item in manyTableData">
                            <!-- 使用陣列渲染復選框組 -->
                            <el-checkbox-group v-model="item.attr_vals">
                                <el-checkbox border :label="val" v-for="(val,i) in item.attr_vals" :key="i"></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>
<!--                    //在頁面中添加upload組件,并設定對應的事件和屬性-->
                    <el-tab-pane label="商品圖片" name="3">
                        <!-- 商品圖片上傳
                        action:指定圖片上傳api介面
                        :on-preview : 當點擊圖片時會觸發該事件進行預覽操作,處理圖片預覽
                        :on-remove : 當用戶點擊圖片右上角的X號時觸發執行
                        :on-success:當用戶點擊上傳圖片并成功上傳時觸發
                        list-type :設定預覽圖片的方式
                        :headers :設定上傳圖片的請求頭 -->
                        <el-upload :action="uploadURL" :on-preview="handlePreview" :on-remove="handleRemove" :on-success="handleSuccess" list-type="picture" :headers="headerObj">
                            <el-button size="small" type="primary">點擊上傳</el-button>
                        </el-upload>
                    </el-tab-pane>
                    <!-- 富文本編輯器組件 -->
                    <el-tab-pane label="商品內容" 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>
<!--        //在el-card卡片視圖下面添加對話框用來預覽圖片-->
        <!-- 預覽圖片對話框 -->
        <el-dialog title="圖片預覽" :visible.sync="previewVisible" width="50%">
            <img :src="previewPath" class="previewImg" />
        </el-dialog>
    </div>
</template>
<script>
    var _ = require('lodash');
    export default {
        data() {
            return {
                //保存步驟條激活項索引
                activeIndex: '0',
                //添加商品的表單資料物件
                addForm: {
                    goods_name: '',
                    goods_price: 0,
                    goods_weight: 0,
                    goods_number: 0,
                    goods_cat: [],
                    //上傳圖片陣列
                    pics: [],
                    //商品的詳情介紹
                    goods_introduce:'',
                    attrs: []
                },
                //上傳圖片的url地址
                uploadURL: 'http://127.0.0.1:8888/api/private/v1/upload',
                //圖片上傳組件的headers請求頭物件
                headerObj: { Authorization: window.sessionStorage.getItem('token') },
                //保存預覽圖片的url地址
                previewPath: '',
                //控制預覽圖片對話框的顯示和隱藏
                previewVisible:false,
                //動態引數串列
                manyTableData: [],
                //靜態屬性串列
                onlyTableData:[],
                //驗證規則
                addFormRules: {
                    goods_name: [
                        { required: true, message: '請輸入商品名稱', trigger: 'blur' }
                    ],
                    goods_price: [
                        { required: true, message: '請輸入商品價格', trigger: 'blur' }
                    ],
                    goods_weight: [
                        { required: true, message: '請輸入商品重量', trigger: 'blur' }
                    ],
                    goods_number: [
                        { required: true, message: '請輸入商品數量', trigger: 'blur' }
                    ],
                    goods_cat: [
                        { required: true, message: '請選擇商品分類', trigger: 'blur' }
                    ]
                },
                //用來保存分類資料
                cateList: [],
                //配置級聯選單中資料如何展示
                cateProps: {
                    value: 'cat_id',
                    label: 'cat_name',
                    children: 'children'
                }
            }
        },
        created() {
            this.getCateList()
        },
        methods: {
            async getCateList() {
                const { data: res } = await this.$http.get('categories')

                if (res.meta.status !== 200) {
                    return this.$message.error('獲取商品分類資料失敗')
                }
                this.cateList = res.data
            },
            handleChange(){
                //如果用戶選擇的不是三級分類,該次選擇無效,因為必須選擇三級分類
                if(this.addForm.goods_cat.length !== 3){
                    this.addForm.goods_cat = []
                    return
                }
            },
            beforeTabLeave (activeName, oldActiveName) {
                // 在tab欄切換之前觸發,兩個形參為切換前,后的tab欄name
                if (oldActiveName === '0') {
                    // 在第一個標簽頁的時候
                    if (this.addForm.goods_cat.length !== 3) {
                        this.$message.error('請選擇商品的分類')
                        return false
                    } else if (this.addForm.goods_name.trim() === '') {
                        this.$message.error('請輸入商品名稱')
                        return false
                    } else if (this.addForm.goods_price === '0') {
                        this.$message.error('請輸入商品價格')
                        return false
                    } else if (this.addForm.goods_weight === '0') {
                        this.$message.error('請輸入商品重量')
                        return false
                    } else if (this.addForm.goods_number === '0') {
                        this.$message.error('請輸入商品數量')
                        return false
                    }
                }
            },
            //  獲取商品引數和屬性
            async tabClicked () {
                if (this.addForm.goods_cat.length === 3) {
                    // 當用戶點擊切換tab欄時觸發
                    if (this.activeIndex === '1') {
                        // 發送請求獲取動態引數
                        const { data: res } = await this.$http.get('categories/' + this.addForm.goods_cat[2] + '/attributes',
                            { params: { sel: 'many' } }
                        )
                        if (res.meta.status !== 200) {
                            return this.$message.error('獲取動態引數串列失敗')
                        }
                        // 將attr_vals字串轉換為陣列
                        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.addForm.goods_cat[2] + '/attributes',
                            { params: { sel: 'only' } }
                        )

                        if (res.meta.status !== 200) {
                            return this.$message.error('獲取靜態屬性串列失敗')
                        }
                        this.onlyTableData = res.data
                    }
                }
            },
            handlePreview(file) {
                //當用戶點擊圖片進行預覽時執行,處理圖片預覽
                //形參file就是用戶預覽的那個檔案
                this.previewPath = file.response.data.url
                //顯示預覽圖片對話框
                this.previewVisible = true
            },
            handleRemove(file) {
                //當用戶點擊X號洗掉時執行
                //形參file就是用戶點擊洗掉的檔案
                //獲取用戶點擊洗掉的那個圖片的臨時路徑
                const filePath = file.response.data.tmp_path
                //使用findIndex來查找符合條件的索引
                const index = this.addForm.pics.findIndex(item => item.pic === filePath)
                //移除索引對應的圖片
                this.addForm.pics.splice(index, 1)
            },
            handleSuccess(response) {
                //當上傳成功時觸發執行
                //形參response就是上傳成功之后服務器回傳的結果
                //將服務器回傳的臨時路徑保存到addForm表單的pics陣列中
                this.addForm.pics.push({ pic: response.data.tmp_path })
            },
            //撰寫點擊事件完成商品添加
            add(){
                this.$refs.addFormRef.validate(async valid=>{
                    if(!valid) return this.$message.error("請填寫必要的表單項!")

                    //將addForm進行深拷貝,避免goods_cat陣列轉換字串之后導致級聯選擇器報錯
                    const form = _.cloneDeep(this.addForm)
                    //將goods_cat從陣列轉換為"1,2,3"字串形式
                    form.goods_cat = form.goods_cat.join(",")
                    //處理attrs陣列,陣列中需要包含商品的動態引數和靜態屬性
                    //將manyTableData(動態引數)處理添加到attrs
                    this.manyTableData.forEach(item=>{
                        form.attrs.push({ attr_id:item.attr_id, attr_value:item.attr_vals.join(" ") })
                    })
                    //將onlyTableData(靜態屬性)處理添加到attrs
                    this.onlyTableData.forEach(item=>{
                        form.attrs.push({ attr_id:item.attr_id, attr_value:item.attr_vals })
                    })

                    //發送請求完成商品的添加,商品名稱必須是唯一的
                    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')
                })
            },
        }
    }
</script>

<style scoped>
    .el-checkbox {
        margin: 0 10px 0 0 !important;
    }
    .previewImg {
        width: 100%;
    }
    .btnAdd {
        margin-top: 15px;
    }
    .el-checkbox {
        margin: 0 10px 0 0 !important;
    }
    .previewImg {
        width: 100%;
    }
    .btnAdd {
        margin-top: 15px;
    }
</style>

3、分類引數

<template>
    <div>
        <!-- 面包屑導航 -->
        <el-breadcrumb separator="/">
            <el-breadcrumb-item :to="{ path: '/home' }">首頁</el-breadcrumb-item>
            <el-breadcrumb-item>商品管理</el-breadcrumb-item>
            <el-breadcrumb-item>分類引數</el-breadcrumb-item>
        </el-breadcrumb>
        <!-- 卡片視圖區域 -->
        <el-card>
            <!-- 警告區域 :closable="false"(是否展示“X”號) show-icon(顯示圖示) -->
            <el-alert title="注意:只允許為第三級分類設定相關引數" type="warning" :closable="false" show-icon>
            </el-alert>

            <!-- 選擇商品分類區域 -->
            <el-row class="cat_opt">
                <el-col>
                    <span>選擇商品分類:</span>
                    <!-- 選擇商品分類的級聯選擇框 -->
                    <el-cascader expandTrigger='hover' v-model="selectedCateKeys" :options="cateList" :props="cateProps" @change="handleChange" clearable></el-cascader>
                </el-col>
                <el-col>
                    <!-- tab頁簽區域 -->
                    <el-tabs v-model="activeName" @tab-click="handleTabClick">
                        <!-- 添加動態引數的面板 將標簽頁改為many -->
                        <el-tab-pane label="動態引數" name="many">
                            <el-button size="mini" type="primary" :disabled="isButtonDisabled" @click="add()">添加引數</el-button>
                            <!-- 添加分類對話框 -->
                            <el-dialog title="添加動態引數" :visible.sync="addCateDialogVisible" width="50%"  @close="addCateDialogClosed">
                                <!-- 添加分類表單 -->
                                <el-form :model="param" label-width="100px">
                                    <el-form-item label="引數名稱" prop="attr_name">
                                        <el-input v-model="param.attr_name"></el-input>
                                    </el-form-item>
                                    <el-form-item label="[only,many]" prop="attr_sel" v-show="false">
                                        <el-input v-model="param.attr_sel">many</el-input>
                                    </el-form-item>
                                    <el-form-item label="引數詳情" prop="attr_vals">
                                        <el-input v-model="param.attr_vals"></el-input>
                                    </el-form-item>

                                </el-form>
                                <span slot="footer" class="dialog-footer">
    <el-button @click="res">取 消</el-button>
    <el-button type="primary" @click="addMany">確 定</el-button>
  </span>
                            </el-dialog>
                            <!-- 動態引數表格 -->
                            <el-table :data="manyTableData" border stripe>
                                <!-- 展開行 -->
                                <el-table-column type="expand">
                                    <template slot-scope="scope">
                                        <!-- 回圈渲染Tag標簽 -->
                                        <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="引數名稱" 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="bj(scope.row.attr_id)">編輯</el-button>
                                        <el-button size="mini" type="danger" icon="el-icon-delete" @click="del(scope.row.attr_id)">洗掉</el-button>
                                    </template>
                                </el-table-column>
                            </el-table>

                        </el-tab-pane>
                        <!-- 添加靜態屬性的面板 將標簽頁改為only -->
                        <el-tab-pane label="靜態屬性" name="only">
                            <el-button size="mini" type="primary" :disabled="isButtonDisabled" @click="oponly">添加屬性</el-button>
                            <el-dialog title="添加靜態屬性" :visible.sync="addCateDialogVisible2" width="50%"  @close="addCateDialogClosed">
                                <!-- 添加分類表單 -->
                                <el-form :model="param" label-width="100px">
                                    <el-form-item label="引數名稱" prop="attr_name">
                                        <el-input v-model="param.attr_name"></el-input>
                                    </el-form-item>
                                    <el-form-item label="[only,many]" prop="attr_sel" v-show="false">
                                        <el-input v-model="param.attr_sel" >only</el-input>
                                    </el-form-item>
                                    <el-form-item label="引數詳情" prop="attr_vals">
                                        <el-input v-model="param.attr_vals"></el-input>
                                    </el-form-item>

                                </el-form>
                                <span slot="footer" class="dialog-footer">
    <el-button @click="res">取 消</el-button>
    <el-button type="primary" @click="addonly">確 定</el-button>
  </span>
                            </el-dialog>
                            <!-- 靜態屬性表格 -->
                            <el-table :data="onlyTableData" border stripe>
                                <!-- 索引列 -->
                                <el-table-column type="index"></el-table-column>
                                <el-table-column label="屬性名稱" 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="bj2(scope.row.attr_id)">編輯</el-button>
                                        <el-button size="mini" type="danger" icon="el-icon-delete" @click="del(scope.row.attr_id)">洗掉</el-button>
                                    </template>
                                </el-table-column>
                            </el-table>
                        </el-tab-pane>
                    </el-tabs>
                </el-col>
            </el-row>
        </el-card>
    </div>
</template>
<script>
    export default {
        data() {
            return {
                addCateDialogVisible:false,
                addCateDialogVisible2:false,
                //分類串列
                cateList: [],
                //用戶在級聯下拉選單中選中的分類id
                selectedCateKeys: [],
                //配置級聯選單中資料如何展示
                cateProps: {
                    value: 'cat_id',
                    label: 'cat_name',
                    children: 'children'
                },
                pid:'',
                param:{
                    attr_name:'',attr_sel:'',attr_vals:''
                },
                //tab頁簽激活顯示的頁簽項
                activeName: 'many',
                //用來保存動態引數資料
                manyTableData: [],
                //用來保存靜態屬性資料
                onlyTableData: []
            }
        },
        created() {
            this.getCateList()
        },
        methods: {
            add(){
                this.pid = '';
                this.addCateDialogVisible = true;
            },
            oponly(){
                this.pid = '';
                this.addCateDialogVisible2 = true;
            },
            res(){
                this.param = {};
                this.addCateDialogVisible = false;
                this.addCateDialogVisible2 = false;
                this.pid = '';
            },
            async addMany(){
                console.log("cateId="+this.cateId);
                console.log("this.pid"+this.pid);
                if (this.pid==''){
                    console.log("新增動態");
                    this.param.attr_sel = "many";
                    const { data: res } = await this.$http.post(`categories/${this.cateId}/attributes`,this.param);
                    if (res.meta.status !== 201) {
                        return this.$message.error('創建動態引數失敗')
                    }
                    this.$message.success('創建動態引數成功');
                }else {
                    console.log("編輯動態");
                    const { data: res } = await this.$http.put(`categories/${this.cateId}/attributes/${this.pid}`,this.param);
                    if (res.meta.status !== 200) {
                        return this.$message.error('編輯動態引數失敗')
                    }
                    this.$message.success('編輯動態引數成功');
                }
                this.handleChange();
                this.param = {};
                this.addCateDialogVisible = false;
            },
            async addonly(){
                console.log("cateId="+this.cateId);
                console.log("this.pid"+this.pid);
                if (this.pid==''){
                    console.log("新增靜態");
                    this.param.attr_sel = "only";
                    const { data: res } = await this.$http.post(`categories/${this.cateId}/attributes`,this.param);
                    if (res.meta.status !== 201) {
                        return this.$message.error('新增靜態失敗')
                    }
                    this.$message.success('新增靜態成功');
                }else {
                    console.log("編輯靜態");
                    const { data: res } = await this.$http.put(`categories/${this.cateId}/attributes/${this.pid}`,this.param);
                    if (res.meta.status !== 200) {
                        return this.$message.error('編輯靜態引數失敗')
                    }
                    this.$message.success('編輯靜態引數成功');
                }

                this.handleChange();
                this.param = {};
                this.addCateDialogVisible2 = false;
            },
            async bj(id){
                console.log("id="+id);
                this.pid = id;
                this.addCateDialogVisible = true;
                const { data: res } = await this.$http.get(`categories/${this.cateId}/attributes/${id}`);
                this.param = res.data;
                if (res.meta.status !== 200) {
                    return this.$message.error('查詢分類失敗')
                }else {
                    this.$message.success('查詢分類成功')
                }
            },
            async bj2(id){
                console.log("id="+id);
                this.pid = id;
                this.addCateDialogVisible2 = true;
                const { data: res } = await this.$http.get(`categories/${this.cateId}/attributes/${id}`);
                this.param = res.data;
                if (res.meta.status !== 200) {
                    return this.$message.error('查詢分類失敗')
                }else {
                    this.$message.success('查詢分類成功')
                }
            },
            del(id){
                this.$confirm('此操作將永久洗掉該檔案, 是否繼續?', '提示', {
                    confirmButtonText: '確定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    console.log("id="+id);
                    console.log(`categories/${this.cateId}/attributes/${id}`)
                    this.$http.delete(`categories/${this.cateId}/attributes/${id}`).then(() => {
                        this.handleChange();
                    }),
                        this.$message({
                            type: 'success',
                            message: '洗掉成功!'
                        });
                }).catch(() => {
                    this.$message({
                        type: 'info',
                        message: '已取消洗掉'
                    });
                });
            },
            async getCateList(){
                //獲取所有的商品分類串列
                const { data: res } = await this.$http.get('categories')

                if (res.meta.status !== 200) {
                    return this.$message.error('獲取分類資料失敗')
                }
                //將資料串列賦值給cateList
                this.cateList = res.data
                // //保存總資料條數
                // this.total = res.data.total
                //   console.log(res.data);
            },
            // 修改原handleChange方法
            async handleChange() {
                // 證明選中的不是三級分類
                if (this.selectedCateKeys.length !== 3) {
                    this.selectedCateKeys = []
                    this.manyTableData = []
                    this.onlyTableData = []
                    return
                }
                // 證明選中的是三級分類
                console.log(this.selectedCateKeys)
                // 根據所選分類的Id,和當前所處的面板,獲取對應的引數
                const { data: res } = await this.$http.get(
                    `categories/${this.cateId}/attributes`,
                    {
                        params: { sel: this.activeName }
                    }
                )
                if (res.meta.status !== 200) {
                    return this.$message.error('獲取引數串列失敗!')
                }
                // 處理文本框中的值
                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
                }
            },
            handleTabClick() {
                console.log(this.activeName)
                this.handleChange()
            },
            //  展示輸入框
            showInput(row){
                //用戶點擊添加按鈕時觸發
                row.inputVisible = true
                //$nextTick:在頁面上元素被重新渲染之后,呼叫回呼函式的代碼
                this.$nextTick.then(()=>{
                    //讓文本框自動獲得焦點
                    this.$refs.saveTagInput.$refs.input.focus()
                })
            },
            handleInputConfirm(row){
                //當用戶在文本框中按下enter鍵或者焦點離開時都會觸發執行
                //判斷用戶在文本框中輸入的內容是否合法
                if(row.inputValue.trim().length===0){
                    row.inputValue = ''
                    row.inputVisible = false
                    return
                }

                // row.inputVisible = false
                //如果用戶輸入了真實合法的資料,需要保存起來
                row.attr_vals.push(row.inputValue.trim())
                row.inputValue = ''
                row.inputVisible = false

                this.saveAttrVals(row)
            },
            handleClose(index,row){
                //洗掉對應索引的引數可選項
                row.attr_vals.splice(index,1)
                //呼叫函式,完成保存可選項的操作
                this.saveAttrVals(row)
            },
            async saveAttrVals(row){
                //封裝函式,完成保存可選項的操作
                //發起請求,保存引數細項
                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('修改引數項失敗')
                }
                this.$message.success('修改引數項成功')
            }
        },
        computed: {
            //添加計算屬性用來獲取按鈕禁用與否
            isButtonDisabled() {
                return this.selectedCateKeys.length !== 3
            },
            //獲取選中的三級分類id
            cateId() {
                if (this.selectedCateKeys.length === 3) {
                    return this.selectedCateKeys[this.selectedCateKeys.length - 1]
                }
                return null
            },

        }
    }
</script>

(6)訂單管理

<template>
    <div>
        <h3>訂單串列</h3>
        <!-- 面包屑導航 -->
        <el-breadcrumb separator="/">
            <el-breadcrumb-item :to="{ path: '/home' }">首頁</el-breadcrumb-item>
            <el-breadcrumb-item>訂單管理</el-breadcrumb-item>
            <el-breadcrumb-item>訂單串列</el-breadcrumb-item>
        </el-breadcrumb>
        <!-- 卡片視圖區域 -->
        <el-card>
            <!-- 搜索欄 -->
            <el-row :gutter="20">
                <el-col :span="8">
                    <el-input placeholder="請輸入內容" v-model="queryInfo.query" clearable>
                        <el-button slot="append" icon="el-icon-search" @click="getOrderList"></el-button>
                    </el-input>
                </el-col>
            </el-row>

            <!-- 訂單表格 -->
            <el-table :data="orderList" border stripe>
                <el-table-column type="index"></el-table-column>
                <el-table-column label="訂單編號" prop="order_number"></el-table-column>
                <el-table-column label="訂單價格" 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="是否發貨" prop="is_send"></el-table-column>
                <el-table-column label="下單時間" prop="create_time">
                    <template slot-scope="scope">
                        {{scope.row.create_time | dateFormat}}
                    </template>
                </el-table-column>
                <el-table-column label="操作" width="125px">
                    <template slot-scope="scope">
                        <!-- 給修改地址按鈕添加點擊事件 -->
                        <el-button size="mini" type="primary" icon="el-icon-edit" @click="showEditAddress(scope.row.order_id)" ></el-button>
                        <!-- 給查看物流添加點擊事件 -->
                        <el-button size="mini" type="success" icon="el-icon-location" @click="showProgress(scope.row.order_id)"></el-button>
                    </template>
                </el-table-column>
            </el-table>

            <!-- 分頁 -->
            <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="queryInfo.pagenum" :page-sizes="[3, 5, 10, 15]" :page-size="queryInfo.pagesize" layout="total, sizes, prev, pager, next, jumper" :total="total">
            </el-pagination>
        </el-card>
        <!-- 修改地址對話框 -->
        <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="省市區縣" prop="address1">
                    <el-cascader :options="cityData" v-model="addressForm.address1"></el-cascader>
                </el-form-item>
                <el-form-item label="詳細地址" 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>
        <!-- 物流資訊進度對話框 -->
        <el-dialog title="物流進度" :visible.sync="progressVisible" width="50%">
            <!-- 時間線組件  -->
            <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
                },
                //訂單串列資料
                orderList: [],
                //資料總條數
                total: 0,
                //控制修改地址對話框的顯示和隱藏
                addressVisible:false,
                //修改識訓地址的表單
                addressForm: {
                    address1: [],
                    address2: ''
                },
                //控制物流進度對話框的顯示和隱藏
                progressVisible: false,
                //保存物流資訊
                progressInfo: [],
                addressFormRules:{
                    address1:[{ required: true, message: '請選擇省市區縣', trigger: 'blur' }],
                    address2:[{ required: true, message: '請輸入詳細地址', trigger: 'blur' }],
                },
                //將匯入的cityData資料保存起來
                cityData:cityData
            }
        },
        created() {
            this.getOrderList()
        },
        methods: {
            async getOrderList() {
                console.log("query="+this.queryInfo.query)
                const { data: res } = await this.$http.get('orders', {
                    params: this.queryInfo
                })

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

                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()
            },
            async showEditAddress(id) {
                //當用戶點擊修改識訓地址按鈕時觸發
                this.addressVisible = true;
                console.log("id="+id);
                const { data: res } = await this.$http.get('orders/'+id);
                this.addressForm = res.data;

            },
            addressDialogClosed(){
                this.$refs.addressFormRef.resetFields()
            },
            async showProgress(id) {
                //發送請求獲取物流資料
                console.log(id)
                const { data: res } = await this.$http.get('/kuaidi/'+id);

                if (res.meta.status !== 200) {
                    return this.$message.error('獲取物流進度失敗!')
                }
                this.progressInfo = res.data
                //顯示對話框
                this.progressVisible = true
            },

        }
    }
</script>

<style lang="less" scoped>
    .el-cascader{
        width: 100%;
    }
</style>

(7)資料統計

<template>
    <div>
        <!-- 面包屑導航區域 -->
        <el-breadcrumb separator-class="el-icon-arrow-right">
            <el-breadcrumb-item :to="{ path: '/home' }">首頁</el-breadcrumb-item>
            <el-breadcrumb-item>資料統計</el-breadcrumb-item>
            <el-breadcrumb-item>資料報表</el-breadcrumb-item>
        </el-breadcrumb>

        <!-- 卡片視圖區域 -->
        <el-card>
            <!-- 2. 為ECharts準備一個具備大小(寬高)的Dom -->
            <div id="main" style="width: 750px;height:400px;"></div>
        </el-card>
    </div>
</template>

<script>
    // 1. 匯入 echarts
    import echarts from 'echarts'
    import _ from 'lodash'

    export default {
        data() {
            return {
                // 需要合并的資料
                options: {
                    title: {
                        text: '用戶來源'
                    },
                    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() {},
        // 此時,頁面上的元素,已經被渲染完畢了!
        async mounted() {
            // 3. 基于準備好的dom,初始化echarts實體
            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('獲取折線圖資料失敗!')
            }

            // 4. 準備資料和配置項
            const result = _.merge(res.data, this.options)
            console.log("result="+result);
            // 5. 展示資料
            myChart.setOption(result)
        },
        methods: {}
    }
</script>

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

轉載請註明出處,本文鏈接:https://www.uj5u.com/qianduan/384299.html

標籤:其他

上一篇:前端JS讀取檔案內容并展示到頁面上

下一篇:js基礎總結 (之前第一天學習js基礎的10000字+總結)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • vue移動端上拉加載

    可能做得過于簡單或者比較low,請各位大佬留情,一起探討技術 ......

    uj5u.com 2020-09-10 04:38:07 more
  • 優美網站首頁,頂部多層導航

    一個個人用的瀏覽器首頁,可以把一下常用的網站放在這里,平常打開會比較方便。 第一步,HTML代碼 <script src=https://www.cnblogs.com/szharf/p/"js/jquery-3.4.1.min.js"></script> <div id="navigate"> <ul> <li class="labels labels_1"> ......

    uj5u.com 2020-09-10 04:38:47 more
  • 頁面為要加<!DOCTYPE html>

    最近因為寫一個js函式,需要用到$(window).height(); 由于手寫demo的時候,過于自信,其實對前端方面的認識也不夠體系,用文本檔案直接敲出來的html代碼,第一行沒有加上<!DOCTYPE html> 導致了$(window).height();的結果直接是整個document的高 ......

    uj5u.com 2020-09-10 04:38:52 more
  • WordPress網站程式手動升級要做好資料備份

    WordPress博客網站程式在進行升級前,必須要做好網站資料的備份,這個問題良家佐言是遇見過的;在剛開始接觸WordPress博客程式的時候,因為升級問題和博客網站的修改的一些嘗試,良家佐言是吃盡了苦頭。因為購買的是西部數碼的空間和域名,每當佐言把自己的WordPress博客網站搞到一塌糊涂的時候 ......

    uj5u.com 2020-09-10 04:39:30 more
  • WordPress程式不能升級為5.4.2版本的原因

    WordPress是一款個人博客系統,受到英文博客愛好者和中文博客愛好者的追捧,并逐步演化成一款內容管理系統軟體;它是使用PHP語言和MySQL資料庫開發的,用戶可以在支持PHP和MySQL資料庫的服務器上使用自己的博客。每一次WordPress程式的更新,就會牽動無數WordPress愛好者的心, ......

    uj5u.com 2020-09-10 04:39:49 more
  • 使用CSS3的偽元素進行首字母下沉和首行改變樣式

    網頁中常見的一種效果,首字改變樣式或者首行改變樣式,效果如下圖。 代碼: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, ......

    uj5u.com 2020-09-10 04:40:09 more
  • 關于a標簽的講解

    什么是a標簽? <a> 標簽定義超鏈接,用于從一個頁面鏈接到另一個頁面。 <a> 元素最重要的屬性是 href 屬性,它指定鏈接的目標。 a標簽的語法格式:<a href=https://www.cnblogs.com/summerxbc/p/"指定要跳轉的目標界面的鏈接">需要展示給用戶看見的內容</a> a標簽 在所有瀏覽器中,鏈接的默認外觀如下: 未被訪問的鏈接帶 ......

    uj5u.com 2020-09-10 04:40:11 more
  • 前端輪播圖

    在需要輪播的頁面是引入swiper.min.js和swiper.min.css swiper.min.js地址: 鏈接:https://pan.baidu.com/s/15Uh516YHa4CV3X-RyjEIWw 提取碼:4aks swiper.min.css地址 鏈接:https://pan.b ......

    uj5u.com 2020-09-10 04:40:13 more
  • 如何設定html中的背景圖片(全屏顯示,且不拉伸)

    1 <style>2 body{background-image:url(https://uploadbeta.com/api/pictures/random/?key=BingEverydayWallpaperPicture); 3 background-size:cover;background ......

    uj5u.com 2020-09-10 04:40:16 more
  • Java學習——HTML詳解(上)

    HTML詳解 初識HTML Hyper Text Markup Language(超文本標記語言) 1 <!--DOCTYPE:告訴瀏覽器我們要使用什么規范--> 2 <!DOCTYPE html> 3 <html lang="en"> 4 <head> 5 <!--meta 描述性的標簽,描述一些 ......

    uj5u.com 2020-09-10 04:40:33 more
最新发布
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 07:59:23 more
  • 生產事故-走近科學之消失的JWT

    入職多年,面對生產環境,盡管都是小心翼翼,慎之又慎,還是難免捅出簍子。輕則滿頭大汗,面紅耳赤。重則系統停擺,損失資金。每一個生產事故的背后,都是寶貴的經驗和教訓,都是專案成員的血淚史。為了更好地防范和遏制今后的各類事故,特開此專題,長期更新和記錄大大小小的各類事故。有些是親身經歷,有些是經人耳傳口授 ......

    uj5u.com 2023-04-18 07:55:04 more
  • 記錄--Canvas實作打飛字游戲

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 打開游戲界面,看到一個畫面簡潔、卻又富有挑戰性的游戲。螢屏上,有一個白色的矩形框,里面不斷下落著各種單詞,而我需要迅速地輸入這些單詞。如果我輸入的單詞與螢屏上的單詞匹配,那么我就可以獲得得分;如果我輸入的單詞錯誤或者時間過長,那么我就會輸 ......

    uj5u.com 2023-04-04 08:35:30 more
  • 了解 HTTP 看這一篇就夠

    在學習網路之前,了解它的歷史能夠幫助我們明白為何它會發展為如今這個樣子,引發探究網路的興趣。下面的這張圖片就展示了“互聯網”誕生至今的發展歷程。 ......

    uj5u.com 2023-03-16 11:00:15 more
  • 藍牙-低功耗中心設備

    //11.開啟藍牙配接器 openBluetoothAdapter //21.開始搜索藍牙設備 startBluetoothDevicesDiscovery //31.開啟監聽搜索藍牙設備 onBluetoothDeviceFound //30.停止監聽搜索藍牙設備 offBluetoothDevi ......

    uj5u.com 2023-03-15 09:06:45 more
  • canvas畫板(滑鼠和觸摸)

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>canves</title> <style> #canvas { cursor:url(../images/pen.png),crosshair; } #canvasdiv{ bo ......

    uj5u.com 2023-02-15 08:56:31 more
  • 手機端H5 實作自定義拍照界面

    手機端 H5 實作自定義拍照界面也可以使用 MediaDevices API 和 <video> 標簽來實作,和在桌面端做法基本一致。 首先,使用 MediaDevices.getUserMedia() 方法獲取攝像頭媒體流,并將其傳遞給 <video> 標簽進行渲染。 接著,使用 HTML 的 < ......

    uj5u.com 2023-01-12 07:58:22 more
  • 記錄--短視頻滑動播放在 H5 下的實作

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 短視頻已經無數不在了,但是主體還是使用 app 來承載的。本文講述 H5 如何實作 app 的視頻滑動體驗。 無聲勝有聲,一圖頂百辯,且看下圖: 網址鏈接(需在微信或者手Q中瀏覽) 從上圖可以看到,我們主要實作的功能也是本文要講解的有: ......

    uj5u.com 2023-01-04 07:29:05 more
  • 一文讀懂 HTTP/1 HTTP/2 HTTP/3

    從 1989 年萬維網(www)誕生,HTTP(HyperText Transfer Protocol)經歷了眾多版本迭代,WebSocket 也在期間萌芽。1991 年 HTTP0.9 被發明。1996 年出現了 HTTP1.0。2015 年 HTTP2 正式發布。2020 年 HTTP3 或能正... ......

    uj5u.com 2022-12-24 06:56:02 more
  • 【HTML基礎篇002】HTML之form表單超詳解

    ??一、form表單是什么

    ??二、form表單的屬性

    ??三、input中的各種Type屬性值

    ??四、標簽 ......

    uj5u.com 2022-12-18 07:17:06 more