vue-cli ElementUI搭建单页面后台(table,form,router,组件传值)(以及中途遇到的 npm打包、axios,第三方插件等问题)

SpringBoot+Vue超市管理系统:一小时极速搭建与核心流程解析 CRUD(增删改查)是后端开发的核心基础,它定义了数据操作的基本范式。其原理是通过RESTful API实现前后端分离架构下的数据交互,前端发送HTTP请求,后端控制器接收并处理,再通过ORM框架与数据库进行交互。掌握CRUD流程的技术价值在于能够构建任何企业级应用的基石,是理解数据流和业务逻辑的关键。在实际应用场景中,诸如超市管理系统这类项目,天然涵盖了商品、订单、库存等模块的完整CRUD操作,是串联数据库设计、后端框架和前端技术的绝佳实践。本文以SpringBoot和Vue2技术栈为例,聚焦于如何快速搭 阅读详情

1、前台展示

首页:

  

添加页:

 

音频列表页:

修改页:

数据统计页:

 

vue可使用 <script> 引入,

这里使用的是npm  vue-cli命令行形式:

2、代码

1.代码结构

2.具体代码

App.vue                                      正常引入php项目组件

<template>
  <div id="app">
    <bar></bar>
  </div>
</template>

<script>
import bar from "./components/Bar";
export default {
  name: "App",
  components: {
    bar
  }
};
</script>

<style>
#app .el-table {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-size: 12px;
}
.el-table td, .el-table th{
  padding: 1px 0;
}
</style>

main.js                   全局环境引入 

注意:css文件引入的位置很重要,决定打包后的自定义 样式覆盖问题

// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import 'element-ui/lib/theme-chalk/index.css'  
import App from './App'
import router from './router'
import ElementUI from 'element-ui'

Vue.config.productionTip = false
Vue.use(ElementUI)
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

router/index.js          路由配置文件  

import Vue from 'vue'
import Router from 'vue-router'
import CateSort from '@/components/routerTemplate/CateSort'
import DataAnalysis from '@/components/routerTemplate/DataAnalysis'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'CateSort',
      component: CateSort
    },
    {
      path: '/CateSort/:id',
      name: 'CateSort',
      component: CateSort
    },
    {
      path: '/DataAnalysis',
      name: 'DataAnalysis',
      component: DataAnalysis
    }
  ]
})

主要组件:

Bar.vue    头部导航栏  ,主要的含路由的地方

<template>
  <div>
    <el-menu :default-active="this.$route.path" router mode="horizontal">
      <el-menu-item index="1">
        <a href="http:/*****n/index.php" target="_blank">首页</a>
      </el-menu-item>
      <el-submenu index="2">
        <template slot="title">{{ check }}</template>
        <el-menu-item index="/CateSort/34">故事</el-menu-item>
        <el-menu-item index="/CateSort/35">儿歌</el-menu-item>
      </el-submenu>
      <el-menu-item>
        <a href="http://******_album.php" target="_blank">待审核专辑</a>
      </el-menu-item>
      <el-menu-item index="/DataAnalysis">数据统计</el-menu-item>
    </el-menu>
    <!-- 路由匹配到的组件将渲染在这里 -->
    <router-view></router-view>
  </div>
</template>

<script>
//el-menu开启路由时 :default-active="this.$route.path" router   ,路由地址替换index中
export default {
  name: "Bar",
  data() {
    return {
      api_url: "htt******ory.php",
      activeIndex: "4",
      check: '分类'
    };
  },
  methods: {}
};
</script>

 catesort.vue          专辑分类列表页(默认展示首页)

<template>
  <div>
    <el-row class="toolList">
      <el-input size="small" placeholder="请输入内容" v-model="tableInit.keyword" class="input"></el-input>
      <el-button icon="el-icon-search" size="small" @click="searchKeyword()">搜索</el-button>
      <el-button type="primary" size="small" @click="addNew()">添加</el-button>
    </el-row>
    <el-table :data="tableData" style="width: 100%" height="650" border>
      <el-table-column prop="id" label="ID" min-width="2" align="center"></el-table-column>
      <el-table-column prop="name" label="专辑名" min-width="5"></el-table-column>
      <el-table-column label="封面图" min-width="3" align="center">
        <template slot-scope="scope">
          <img :src="scope.row.pic" width="50" height="50" class="head_pic" />
        </template>
      </el-table-column>
      <el-table-column prop="desc" label="简介" min-width="10"></el-table-column>
      <!-- <el-table-column prop="user_num" label="用户数" min-width="2" align="center"></el-table-column> -->
      <el-table-column prop="real_num" label="收听数" min-width="3" align="center"></el-table-column>
      <el-table-column prop="cate_name" label="分类" min-width="3" align="center"></el-table-column>
      <el-table-column prop="age_name" label="年龄段" min-width="3" align="center"></el-table-column>
      <el-table-column prop="recom" label="排序" min-width="2" align="center"></el-table-column>
      <el-table-column min-width="8" align="center" label="操作">
        <template slot-scope="scope">
          <el-button size="mini" @click="openModify(scope.$index, scope.row)">修改</el-button>
          <el-button size="mini" @click="mp3List(scope.$index, scope.row)">音频列表</el-button>
          <el-button size="mini" type="danger" @click="handleDelete(scope.$index, scope.row)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    <!-- 主体表格 -->
    <el-pagination
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :current-page="tableInit.currentPage"
      :page-sizes="[10, 20, 50, 100]"
      :page-size="tableInit.limit"
      layout="total, sizes, prev, pager, next, jumper"
      :total="tableInit.total"
    ></el-pagination>
    <!-- 页码 -->
    <el-dialog
      title="新增音频/专辑"
      width="50%"
      top="5vh"
      :visible.sync="dialogTableVisible"
      center
      :append-to-body="true"
      :lock-scroll="false"
      :close-on-click-modal="false"
    >
      <UploadForm></UploadForm>
    </el-dialog>
    <!-- 新增dialog -->
    <el-dialog
      :title="dialogModify.title"
      width="50%"
      top="5vh"
      :visible.sync="dialogModify.Visible"
      center
      :append-to-body="true"
      :lock-scroll="false"
      :close-on-click-modal="false"
      :before-close="resetForm"
    >
      <ModifyForm :albumInfo="dialogModify.albumInfo" v-on:childByValue="childByValue"></ModifyForm>
    </el-dialog>
    <!-- 修改专辑dialog -->
    <el-dialog
      :title="dialogMp3List.title"
      width="80%"
      top="2vh"
      :visible.sync="dialogMp3List.Visible"
      center
      :append-to-body="true"
      :lock-scroll="false"
      :close-on-click-modal="false"
      :before-close="resetForm"
    >
      <AudioList :mp3Info="dialogMp3List.mp3Info" v-on:childByValue="childByValue"></AudioList>
    </el-dialog>
    <!-- 音频列表dialog -->
  </div>
</template>

<script>
import axios from "axios";
import UploadForm from "../cateTemplate/UploadForm";
import ModifyForm from "../cateTemplate/ModifyForm";
import AudioList from "../cateTemplate/AudioList";
export default {
  name: "Bar",
  components: { UploadForm, ModifyForm, AudioList }, //新增专辑、音频页面
  data() {
    return {
      api_url: "http://*****ry.php",
      tableInit: {
        limit: 10,
        currentPage: 1,
        cate: 34,
        total: 900,
        keyword: "" //搜索关键词
      },
      tableData: [], //表格数据
      dialogTableVisible: false, //模态框状态
      dialogModify: {
        Visible: false, //修改模态框状态
        title: "",
        albumInfo: {}
      },
      dialogMp3List: {
        Visible: false, //mp3list修改模态框状态
        title: "",
        albumInfo: {}
      }
    };
  },
  created: function() {
    var that = this;
    that.tableInit.cate = that.$route.params.id;
    that.changeCateOrPage(1);
  },
  watch: {
    $route(to, from) {
      var that = this;
      that.tableInit.cate = that.$route.params.id;
      that.tableInit.currentPage = 1;
      that.tableInit.keyword = "";
      that.changeCateOrPage(1);
    }
  },
  methods: {
    childByValue: function(childValue) {
      // childValue就是子组件传过来的值
      this.dialogModify.Visible = childValue;
    },
    //修改模态框关闭时回掉
    resetForm(done) {
      //this.$refs["modifyForm"].resetFields();
      done();
    },
    //删除功能
    handleDelete(a, b) {
      var that = this;
      that
        .$confirm("此操作将删除该专辑, 是否继续?", "提示", {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning"
        })
        .then(() => {
          axios
            .get(that.api_url, {
              params: {
                method: "delete_album",
                id: b.id
              }
            })
            .then(function(response) {
              that.tableData.splice(a, 1);
              if (response.data.ret) {
                that.$message({
                  duration: 1000,
                  message: response.data.msg,
                  type: "success"
                });
              } else {
                that.$message.error(response.data.msg);
              }
            })
            .catch(function(error) {
              console.log(error);
            });
        })
        .catch(() => {
          that.$message({
            type: "info",
            message: "已取消删除"
          });
        });
    },
    //搜索功能
    searchKeyword() {
      var that = this;
      that.tableInit.currentPage = 1;
      that.changeCateOrPage(1);
    },
    //显示新增专辑音频组件
    addNew() {
      this.dialogTableVisible = true; //默认页面不显示为false,点击按钮将这个属性变成true
    },
    //显示修改专辑组件
    openModify(a, b) {
      var that = this;
      that.$nextTick(() => {
        that.dialogModify.Visible = true; //默认页面不显示为false,点击按钮将这个属性变成true
        that.dialogModify.title = "《" + b.name + "》修改";
        that.dialogModify.albumInfo = b;
      });
    },
    //展示mp3list
    mp3List(a, b) {
      var that = this;
      that.$nextTick(() => {
        that.dialogMp3List.Visible = true; //默认页面不显示为false,点击按钮将这个属性变成true
        that.dialogMp3List.title = "《" + b.name + "》音频列表";
        that.dialogMp3List.mp3Info = b;
      });
    },
    //修改每页条数
    handleSizeChange(val) {
      var that = this;
      that.tableInit.limit = val;
      that.tableInit.currentPage = 1;
      that.changeCateOrPage(1);
    },
    //翻页
    handleCurrentChange(val) {
      var that = this;
      that.changeCateOrPage(val);
    },
    changeCateOrPage(page) {
      var that = this;
      axios
        .get(that.api_url, {
          params: {
            method: "get_story_album_list",
            cate: that.tableInit.cate,
            page: page,
            limit: that.tableInit.limit,
            keyword: that.tableInit.keyword
          }
        })
        .then(function(response) {
          that.tableData = response.data.data;
          that.tableInit.total = Number(response.data.count);
        })
        .catch(function(error) {
          console.log(error);
        });
    }
  }
};
</script>
<style>
.toolList {
  padding-top: 5px;
  padding-bottom: 5px;
}
.input {
  width: 200px !important;
}
</style>

cateTemplate/uploadform.vue         新增页面   

注意:form表单提交时 post方式以及数据类型需要调整调整  qs

<template>
  <el-form
    :rules="rules"
    ref="form"
    :model="form"
    :hide-required-asterisk="true"
    label-width="80px"
  >
    <el-form-item label="类型">
      <el-switch
        v-model="form.delivery"
        active-text="新增专辑"
        inactive-text="新增音频"
        @change="typeChange"
      ></el-switch>
    </el-form-item>
    <!-- 操作分类 -->
    <div v-if="form.delivery">
      <el-form-item label="封面图">
        <el-upload
          class="avatar-uploader"
          accept="image/jpg, image/jpeg"
          :action="api_url"
          :data="{method:'upload',type:'images'}"
          :show-file-list="false"
          :on-success="handleAvatarSuccess"
          :before-upload="beforeAvatarUpload"
        >
          <div
            slot="tip"
            class="el-upload__tip"
            style="line-height: 5px;"
          >注意:请上传jpg/jpeg类型,且宽高比为1:1 的图片</div>
          <img v-if="form.imageUrl" :src="form.imageUrl" class="avatar">
          <i v-else class="el-icon-plus avatar-uploader-icon"></i>
        </el-upload>
      </el-form-item>
      <el-form-item label="专辑名" prop="name">
        <el-input v-model="form.name"></el-input>
      </el-form-item>
      <el-form-item label="专辑描述" prop="desc">
        <el-input type="textarea" :rows="2" placeholder="请输入内容" v-model="form.desc"></el-input>
      </el-form-item>
      <el-form-item label="分类" prop="album">
        <el-select v-model="form.album" placeholder="请选择专辑分类">
          <el-option label="故事" value="34"></el-option>
          <el-option label="儿歌" value="35"></el-option>
        </el-select>
      </el-form-item>
      <el-form-item label="年龄段" prop="age">
        <el-select v-model="form.age" placeholder="请选择年龄段">
          <el-option label="孕期" value="1"></el-option>
          <el-option label="0-3岁" value="2"></el-option>
          <el-option label="3-6岁" value="3"></el-option>
        </el-select>
      </el-form-item>
    </div>
    <!-- 新增专辑 -->
    <div v-else>
      <el-row>
        <el-col :span="7">
          <el-form-item label="专辑名">
            <el-select v-model="album" placeholder="请选择分类" @change="searchAlbum">
              <el-option label="故事" value="34"></el-option>
              <el-option label="儿歌" value="35"></el-option>
            </el-select>
          </el-form-item>
        </el-col>
        <el-col :span="8">
          <el-form-item prop="album_id" label-width="10px">
            <el-select v-model="form.album_id" filterable placeholder="请选择专辑">
              <el-option v-for="item in options" :key="item.id" :label="item.name" :value="item.id"></el-option>
            </el-select>
          </el-form-item>
        </el-col>
      </el-row>
    </div>
    <el-form-item label="音频文件">
      <el-upload
        class="upload-demo"
        ref="upload"
        accept="audio/mpeg"
        :action="api_url"
        :data="{method:'upload',type:'mp3'}"
        :on-preview="handlePreview"
        :on-remove="handleRemove"
        :on-success="handelSuccess"
        :file-list="fileList"
        :auto-upload="true"
        :multiple="true"
      >
        <el-button slot="trigger" size="small" type="primary">选取文件</el-button>
        <div slot="tip" class="el-upload__tip">注意:多选,音频文件名即是在app播放列表中音频名,请确定好文件名再上传!</div>
      </el-upload>
    </el-form-item>
    <!-- 添加音频 -->
    <el-form-item>
      <el-button type="primary" @click="submitForm('form')">立即提交</el-button>
      <!-- <el-button @click="resetForm()">重置</el-button> -->
    </el-form-item>
    <!-- 提交 -->
  </el-form>
</template>
<script>
import { type } from "os";
import axios from "axios";
import qs from "qs";
export default {
  data() {
    return {
      api_url: "http******y.php",
      album: "",
      fileList: [],
      //表单数据
      form: {
        name: "",
        desc: "",
        delivery: false,
        imageUrl: "",
        album_id: "",
        mp3_url_arr: []
      },
      options: "",
      //验证规则
      rules: {
        name: [
          { required: true, message: "请输入专辑名称", trigger: "blur" },
          { min: 1, max: 50, message: "长度在 1 到 50 个字符", trigger: "blur" }
        ],
        age: [{ required: true, message: "请选择年龄段", trigger: "change" }],
        album: [{ required: true, message: "请选择分类", trigger: "change" }],
        album_id: [
          { required: true, message: "请选择特定专辑", trigger: "change" }
        ],
        desc: [{ required: true, message: "请填写专辑描述", trigger: "blur" }]
      }
    };
  },
  methods: {
    //获取专辑列表
    searchAlbum(cate_id) {
      var that = this;
      axios
        .get(that.api_url, {
          params: {
            method: "get_album",
            cate_id: cate_id
          }
        })
        .then(function(response) {
          that.options = response.data.data;
        })
        .catch(function(error) {
          console.log(error);
        });
    },
    //类型修改重置表单值
    typeChange(type) {
      this.$refs["form"].resetFields();
    },
    //封面图方法
    handleAvatarSuccess(res, file) {
      //this.form.imageUrl = URL.createObjectURL(file.raw);
      if (res.code) {
        this.form.imageUrl = res.data.url;
        this.$message({
          message: res.msg,
          type: "success"
        });
      } else {
        this.$message({
          message: res.msg,
          type: "warning"
        });
      }
    },
    beforeAvatarUpload(file) {
      const isJPG = file.type === "image/jpeg";
      const isLt2M = file.size / 1024 / 1024 < 2;
      if (!isLt2M) {
        this.$message.error("上传图片大小不能超过 2MB!");
      }
      return isJPG && isLt2M;
    },
    //音频方法
    handleRemove(file, fileList) {
      this.form.mp3_url_arr = [];
      fileList.forEach(item => {
        this.form.mp3_url_arr.push({
          name: item.response.data.name,
          url: item.response.data.url,
          dura: item.response.data.dura
        });
      });
    },
    handlePreview(file) {
      console.log(file);
    },
    handelSuccess(response, file, fileList) {
      this.form.mp3_url_arr.push({
        name: response.data.name,
        url: response.data.url,
        dura: response.data.dura
      });
    },
    //提交
    submitForm(formName) {
      var that = this;
      this.$refs[formName].validate(valid => {
        if (valid) {
          if (that.form.delivery && that.form.imageUrl == "") {
            this.$message({
              message: "封面图不能为空!",
              type: "warning"
            });
            return false;
          }

          axios
            .post(
              that.api_url,
              qs.stringify({
                method: "save_story",
                form_data: that.form
              }),
              {
                headers: { "Content-Type": "application/x-www-form-urlencoded" } //post
              }
            )
            .then(function(response) {
              if (response.data.ret) {
                that.$message({
                  duration: 1000,
                  message: response.data.msg,
                  type: "success",
                  onClose: function() {
                    window.location.reload();
                  }
                });
              } else {
                that.$message.error(response.data.msg);
              }
            })
            .catch(function(error) {
              console.log(error);
            });
        } else {
          console.log("error submit!!");
          return false;
        }
      });
    },
    resetForm() {
      this.$message({
        duration: 1000,
        message: "ceshihhhhhhh",
        type: "success",
        onClose: function() {
          window.location.reload();
        }
      });
    }
  }
};
</script>

<style>
.avatar-uploader .el-upload {
  border: 1px dashed #d9d9d9;
  border-radius: 6px;
  cursor: pointer;
  position: relative;
  overflow: hidden;
}
.avatar-uploader .el-upload:hover {
  border-color: #409eff;
}
.avatar-uploader-icon {
  font-size: 28px;
  color: #8c939d;
  width: 100px;
  height: 100px;
  line-height: 100px;
  text-align: center;
}
.avatar {
  width: 100px;
  height: 100px;
  display: block;
}
</style>

 cateTemplate/AudioList.vue、modifyForm.vue、modifyBoxForm.vue 与新增表单相似

音频 audio标签的使用

      <el-table-column label="音频" min-width="8" align="center">
        <template slot-scope="scope">
          <audio ref="audio" controls="controls" type="audio/mpeg" :src="scope.row.high_url"></audio>
        </template>
      </el-table-column>

 

DataAnalysis.vue      数据统计组件,简单的列表页

<template>
  <div>
    <el-table :data="tableData" style="width: 100%" height="650" border>
      <el-table-column prop="day" label="日期" min-width="2" align="center"></el-table-column>
      <el-table-column prop="view_num" label="收听数" min-width="5"></el-table-column>
      <el-table-column prop="user_num" label="用户量" min-width="3" align="center"></el-table-column>
      <el-table-column min-width="5" align="center" label="操作">
        <template slot-scope="scope">
          <el-button size="mini" @click="openDetail(scope.$index, scope.row)">详情</el-button>
        </template>
      </el-table-column>
    </el-table>
    <!-- 主体表格 -->
    <el-pagination
      @size-change="handleSizeChange"
      @current-change="handleCurrentChange"
      :current-page="tableInit.currentPage"
      :page-sizes="[50, 100]"
      :page-size="tableInit.limit"
      layout="total, sizes, prev, pager, next, jumper"
      :total="tableInit.total"
    ></el-pagination>
    <!-- 页码 -->
    <el-dialog
      :title="dialogModify.title"
      width="98%"
      top="1vh"
      :visible.sync="dialogModify.Visible"
      center
      :append-to-body="true"
      :lock-scroll="false"
      :close-on-click-modal="false"
      :before-close="resetForm"
    >
      <LogDetail :day="dialogModify.day" v-on:childByValue="childByValue"></LogDetail>
    </el-dialog>
    <!-- 修改专辑dialog -->
  </div>
</template>

<script>
import axios from "axios";
import LogDetail from "../logTemplate/LogDetail";
export default {
  components: { LogDetail},
  data() {
    return {
      api_url: "http://b***ory.php",
      tableInit: {
        limit: 50,
        currentPage: 1,
        cate: 34,
        total: 900,
        keyword: "" //搜索关键词
      },
      tableData: [], //表格数据
      dialogModify: {
        Visible: false, //修改模态框状态
        day: "",
      }
    };
  },
  created: function() {
    var that = this;
    that.changePage(1);
  },
  watch: {
  },
  methods: {
    childByValue: function(childValue) {
      // childValue就是子组件传过来的值
      this.dialogModify.Visible = childValue;
    },
    //修改模态框关闭时回掉
    resetForm(done) {
      //this.$refs["modifyForm"].resetFields();
      done();
    },
    //显示修改专辑组件
    openDetail(a, b) {
      var that = this;
      that.$nextTick(() => {
        that.dialogModify.Visible = true; //默认页面不显示为false,点击按钮将这个属性变成true
        that.dialogModify.title = '详情';
        that.dialogModify.day = b.day;
      });
    },
    //修改每页条数
    handleSizeChange(val) {
      var that = this;
      that.tableInit.limit = val;
      that.tableInit.currentPage = 1;
      that.changePage(1);
    },
    //翻页
    handleCurrentChange(val) {
      var that = this;
      that.changePage(val);
    },
    changePage(page) {
      var that = this;
      axios
        .get(that.api_url, {
          params: {
            method: "get_story_log_list",
            page: page,
            limit: that.tableInit.limit
          }
        })
        .then(function(response) {
          that.tableData = response.data.data;
          that.tableInit.total = Number(response.data.count);
        })
        .catch(function(error) {
          console.log(error);
        });
    }
  }
};
</script>
<style>
.toolList {
  padding-top: 5px;
  padding-bottom: 5px;
}
.input {
  width: 200px;
}
</style>

LogDetail.vue 专辑排行 与 音频排行组件  主要是两张表,以及切换日期。

<template>
  <div>
    <el-row class="f_row">
      <el-col :span="2" v-for="(item,i) in dated_list" :key="i">
        <el-button
          v-if="i === check"
          type="primary"
          size="mini"
          round
          @click="changeDay(item,i)"
        >{{ item }}</el-button>
        <el-button v-else size="mini" round @click="changeDay(item,i)">{{ item }}</el-button>
      </el-col>
    </el-row>
    <el-row :gutter="20">
      <el-col :span="11">
        <AlbumLog :day="detailDay"></AlbumLog>
      </el-col>
      <el-col :span="13">
        <BoxLog :day="detailDay"></BoxLog>
      </el-col>
    </el-row>
  </div>
</template>

<script>
import axios from "axios";
import AlbumLog from "./AlbumLog";
import BoxLog from "./BoxLog";
export default {
  props: {
    day: {}
  },
  components: { AlbumLog, BoxLog },
  data() {
    return {
      api_url: "http://b*****ry.php",
      dated_list: [],
      detailDay: "",
      check: 2
    };
  },
  created: function() {
    var that = this;
    that.detailDay = that.day;
    that.getDated(that.day);
  },
  watch: {
    day(newValue, oldValue) {
      var that = this;
      that.day = newValue;
      that.detailDay = newValue;
      that.getDated(newValue);
    }
  },
  methods: {
    childByValue: function(childValue) {
      // childValue就是子组件传过来的值
      this.dialogModify.Visible = childValue;
    },
    //修改模态框关闭时回掉
    resetForm(done) {
      //this.$refs["modifyForm"].resetFields();
      done();
    },
    //切换日期
    changeDay(day, i) {
      var that = this;
      that.detailDay = day;
      that.check = i;
    },
    //获取日期
    getDated(day) {
      var that = this;
      axios
        .get(that.api_url, {
          params: {
            method: "get_dated",
            day: day
          }
        })
        .then(function(response) {
          that.dated_list = response.data;
        })
        .catch(function(error) {
          console.log(error);
        });
    }
  }
};
</script>
<style>
.f_row {
  padding-bottom: 5px;
}
.el-table {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-size: 12px;
}
.el-link {
  font-family: "Avenir", Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  font-size: 12px;
}
</style>

 BoxLog.vue  与 AlbumLog.vue  结构一样

<template>
  <div>
    <el-table :data="tableData" style="width: 100%" height="600" border>
      <el-table-column type="index" width="40%"></el-table-column>
      <el-table-column prop="box_id" label="id" min-width="3" align="center"></el-table-column>
      <el-table-column prop="box_name" label="音频名" min-width="5"></el-table-column>
      <el-table-column prop="view_num" label="收听数" min-width="3" align="center"></el-table-column>
      <el-table-column prop="cate_name" label="分类" min-width="3" align="center"></el-table-column>
      <el-table-column prop="age_name" label="年龄" min-width="3" align="center"></el-table-column>
      <el-table-column prop="album_name" label="专辑名" min-width="5">
        <template slot-scope="scope">
          <el-link type="primary"  @click="openAlbumBox(scope.$index, scope.row)">{{ scope.row.album_name }}</el-link>
        </template>
      </el-table-column>
    </el-table>
    <!-- 主体表格 -->
  
    <el-dialog
      :title="dialogModify.title"
      width="75%"
      top="2vh"
      :visible.sync="dialogModify.Visible"
      center
      :append-to-body="true"
      :lock-scroll="false"
      :close-on-click-modal="false"
      :before-close="resetForm"
    >
      <AlbumBox :ListInfo="dialogModify.ListInfo" v-on:childByValue="childByValue"></AlbumBox>
    </el-dialog>
    <!-- 修改专辑dialog -->
  </div>
</template>

<script>
import axios from "axios";
import AlbumBox from "./AlbumBox";
export default {
  props: {
    day: {}
  },
  components: {AlbumBox},
  data() {
    return {
      api_url: "http:/*****tory.php",
      tableInit: {
        limit: 100,
        currentPage: 1,
        cate: 34,
        total: 900,
        keyword: "" //搜索关键词
      },
      tableData: [], //表格数据
      dialogModify: {
        Visible: false, //修改模态框状态
      }
    };
  },
  created: function() {
    var that = this;
    that.changePage(1);
  },
  watch: {
    day(newValue, oldValue) {
      var that = this;
      that.day = newValue;
      that.changePage(1);
    }
  },
  methods: {
    childByValue: function(childValue) {
      // childValue就是子组件传过来的值
      this.dialogModify.Visible = childValue;
    },
    //修改模态框关闭时回掉
    resetForm(done) {
      //this.$refs["modifyForm"].resetFields();
      done();
    },
    //显示专辑音频列表
    openAlbumBox(a, b) {
      var that = this;
      b.day = that.day;
      that.$nextTick(() => {
        that.dialogModify.Visible = true; //默认页面不显示为false,点击按钮将这个属性变成true
        that.dialogModify.title = "《"+b.album_name+"》"+b.age_name+","+b.cate_name;
        that.dialogModify.ListInfo = b;
      });
    },
    //修改每页条数
    handleSizeChange(val) {
      var that = this;
      that.tableInit.limit = val;
      that.tableInit.currentPage = 1;
      that.changePage(1);
    },
    //翻页
    handleCurrentChange(val) {
      var that = this;
      that.changePage(val);
    },
    changePage(page) {
      var that = this;
      axios
        .get(that.api_url, {
          params: {
            method: "get_story_box_log_list",
            page: page,
            limit: that.tableInit.limit,
            day: that.day
          }
        })
        .then(function(response) {
          that.tableData = response.data.data;
          that.tableInit.total = Number(response.data.count);
        })
        .catch(function(error) {
          console.log(error);
        });
    }
  }
};
</script>
<style>
.toolList {
  padding-top: 5px;
  padding-bottom: 5px;
}
</style>

 

2、问题:

     打包遇到的问题

      a、npm run build  打包时存储目录需要修改:

config文件夹下的index.js


    // Template for index.html
    index: path.resolve(__dirname, '../dist/index.html'),

    // Paths
    assetsRoot: path.resolve(__dirname, '../dist'),
    assetsSubDirectory: 'static',
    assetsPublicPath: './',//修改为相对路径当前文件夹下

b、修改build-webpack.base.conf.js,解决引入字体图标,比如font-awesome的图标路径出错的问题,在webpack.base.conf.js里面修改limit要改大,把10000改为90000。

规范性验证!!!

去除eslint验证,修改修改webpack.base.conf.js,注释下面那行! 或者在初始化的时候不选择eslint

    rules: [
      // ...(config.dev.useEslint ? [createLintingRule()] : []),
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: vueLoaderConfig
      },

引入element-ui(文档很清楚)

element-ui

  • 加载element-ui:
npm install element-ui --save-dev 
#或者 npm i element-ui -S
  • 配置element-ui: 在main.js中引入element.js和样式
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
import Vue from 'vue'
import App from './App'
import router from './router'
import ElementUI from 'element-ui'   //引入element
import 'element-ui/lib/theme-chalk/index.css'
//import axios from 'axios'
//import VueAxios from 'vue-axios'

Vue.config.productionTip = false
//Vue.use(ElementUI,VueAxios,axios)
Vue.use(ElementUI)
/* eslint-disable no-new */
new Vue({
  el: '#app',
  router,
  components: { App },
  template: '<App/>'
})

webpack打包进行丑化压缩遇到(TypeError: Cannot read property 'compilation' of undefined)问题

安装环境的使用一定要-save-dev或者是-save!!!!

版本升级或降级

1、npm i uglifyjs-webpack-plugin@1.0.0 --save

2、npm i optimize-css-assets-webpack-plugin@2 --save

Vue axios发post请求后台接收不到参数(有多种方式,这里使用qs转换):

【引入 qs ,这个库是 axios 里面包含的,不需要再下载了】
 

import qs from 'qs'
          axios
            .post(
              that.api_url,
              qs.stringify({
                method: "save_story",
                form_data: that.form
              }),
              {
                headers: { "Content-Type": "application/x-www-form-urlencoded" } //post
              }
            )
            .then(function(response) {
              console.log(response.data);
              if (response.data.ret) {
                that.$message({
                  duration: 1000,
                  message: response.data.msg,
                  type: "success",
                  onClose: function() {
                    window.location.reload();
                  }
                });
              } else {
                that.$message.error(response.data.msg);
              }
            })
            .catch(function(error) {
              console.log(error);
            });
vue-element-admin中文版,加上匹配的node版本 vue-element-admin中文版,加上匹配的node版本 nvm ls //显示所有npm版本 nvm install 16.20.2 //安装新版本node,如果有该版本则可以不安装 nvm use 16.20.2 //设置为当前版本 npm install npm run dev //启动调试 立即下载

相关推荐

【3D计算机视觉】从PointNet到PointNet++理论及pytorch代码

从PointNet到PointNet++理论及代码详解1. 点云是什么1.1 三维数据的表现形式1.2 为什么使用点云1.3 点云上以往的相关工作2. PointNet2.1 基于点云的置换不变性2.1.1 由对称函数到PointNet(vanilla)2.1.2 理论证明2.2 基于点云的旋转不变性2.3 网络总体结构2.4 实验结果和网络的鲁棒性2.5 代码解析3. PointNet++3.1...

小执着的博客 8万+

vue + element 实现可编辑列表(超详细)

vue + element 实现可编辑列表(超详细) 1.适用场景 ​ 当我们对于主子表数据同时保存的时候,我们又不想做弹窗一条一条的新增子表数据的时候,并且子表数据并不是特别复杂,完全可用table来操作,这种情况下可选择可编辑列表来完成主子表的同时操作。 2.功能简介 ​ 基于Tlement-Table编写,并借助于一些表单元素控件。实现表格数据的填写。以及表格操作,包括:新增行,删除行,插入行,上移,下移,置顶,置底等功能。废话不多说直接上代码。 3.页面布局 ​ 包含对每一行数据的简单校验。 &lt

Arthur19931016的博客 9328

Win10自动更新怎么永久关闭?有效的Win10强制更新关闭方法

之前小编为大家分享过一些Win10彻底关闭Windows Update自动更新的方法,主要是通过一些如设置流量计费或借助一些专门的小工具来实现,但往往会发现,Win10自动更新就像打不死的小强,不管怎么关闭,之后还是会自动更新,让不少小伙伴颇为不爽。今天小编带来了这篇改进型教程,通过全方位设置,彻底关闭Win10自动更新,感兴趣的小伙伴不妨试试吧。 ...

jianai0602的博客 108万+

vue+element-ui实现表格里嵌套表格

效果图:点击某行数据展开另一个嵌套在里面的table 核心代码: 从后台请求的数据格式: 代码实现: <template> <div> <div class="assetnum"> <div class="assetbox br pr30"> <div class="ass...

鲁小班的博客 2万+

Python爬虫实战:高效爬取CNKI知网文献数据的技术解析

本文将详细介绍如何使用Python最新技术构建一个高效的CNKI知网文献爬虫系统。我们将从爬虫基础知识讲起,逐步深入到高级反反爬技术、分布式爬取、智能解析等前沿内容。文章包含完整的代码实现,涵盖请求模拟、数据解析、持久化存储等关键环节,并特别针对CNKI的反爬机制提供解决方案。通过本文,读者将掌握构建专业级学术文献爬虫的全套技术栈。关键词:Python爬虫、CNKI爬取、反反爬技术、文献数据挖掘、Scrapy框架本文详细介绍了如何使用Python最新技术构建CNKI知网文献爬虫。

2201_76125261的博客 2075

快速卷积结构FIR数字滤波器的设计与ARM平台实现

本文提出了一种基于快速卷积结构的FIR数字滤波器设计与实现方案。通过Matlab设计了满足特定指标的低通FIR滤波器,采用重叠-保存法和重叠-相加法两种快速卷积算法,将计算复杂度从O(N·M)降低到O(NlogN)。详细介绍了滤波器系数生成、性能验证流程,并提供了ARM平台C语言实现的关键技术,包括定点量化处理。实验结果表明,该方法能有效滤除混合信号中的高频干扰,保留目标1kHz正弦信号,验证了设计方案的有效性。

huanghm88的专栏 122

Vue+ElementUI 实现主页面传数据列表到子组件的el-table表格进行数据回显(勾选)

实现效果 在主页面引入自定义弹窗组件,点击按钮打开弹窗,选中列表数据点击确定后返回数据到主页面展示。在主页面可以对列表数据进行删除操作,删除后再打开弹窗时要实现删除的数据取消选中,未删除的保持勾选状态。 主页面为前面实现的列表展开收起页(点击查看) 点击打开弹窗 现在选中了三个事项 点击删除按钮删除一个 再次打开弹窗,未删除的数据回显勾选,被删除的数据已取消选中 弹窗组件代码 数据都是造的数据,未对接接口 <template> <div>

此人很懒,什么都没有写 5266

UNet改进(52):轴向+代理注意力让UNet既轻快又精准

本文提出了一种改进的UNet架构,通过引入轴向注意力代理模块增强医学图像分割性能。该模块将二维自注意力分解为行列两个一维注意力操作,结合可学习代理节点进行全局信息聚合,在保持计算效率的同时提升模型对长距离依赖的建模能力。实验表明,该方法在多个医学图像数据集上较传统UNet提升3.2%-5.7%的Dice系数,边界质量显著改善。该方案特别适用于具有方向性结构的医学图像分割任务,如血管、器官等,在计算复杂度和分割精度之间实现了良好平衡。

2501_91516851的博客 327

解决vue elementUI 弹框Dialog 打开后滚条回到顶部

<el-dialog :lock-scroll="false" :append-to-body="true" > </el-dialog > append-to-body Dialog 自身是否插入至 body 元素上。嵌套的 Dialog 必须指定该属性并赋值为 true boolean — false lock-scroll 是否在 Dialog 出现时将 body 滚动锁定 boolean — true ...

qq_44146522的博客 4091

【实战项目开发技术分享】如何设置机器人禁行区/虚拟墙

在现代机器人技术的日益发展中,路径规划是使机器人在复杂环境中安全、高效移动的关键部分。其中一个重要的问题是如何划定机器人的禁行区,以确保机器人不会进入危险区域或无法到达的地方。在本文中,我们将探讨一些关键策略,帮助机器人算法工程师更好地划定禁行区。代价地图可以通过多层叠加来实现,一般包括以下几个层级:静态地图层(Static Map Layer):由SLAM(Simultaneous Localization and Mapping)构建的静态地图。该层包含了环境中固定不变的地物信息,如墙壁、家具等。

xiewf的博客 1万+

化工管道设计软件:CAESAR II二次开发_(6).API接口与函数库

自定义函数库是开发者根据特定需求编写的函数集合。这些函数可以扩展CAESAR II的功能,实现更复杂的管道设计任务。自定义函数库通常需要开发者具备一定的编程基础,能够理解和编写与CAESAR II接口兼容的代码。定义函数:在Python或其他编程语言中定义所需的函数。注册函数:将自定义函数注册到CAESAR II的函数库中。调用函数:在CAESAR II中调用自定义函数,实现特定功能。假设我们需要创建一个自定义函数库,用于批量修改管道节点的坐标。定义函数:在Python中定义一个函数,用于批量修改节点坐标。

kkchenjj的博客 1728

VUE父子页面传递数据

VUE通过父页面向子对话框中传数据。 在代码中通过tasksinfo变量来传递参数。 子对话框和父页面是在两个不同的vue文件中写的。 子对话框代码:声明变量tasksinfo。 <el-dialog :title="dialogTitle" :visible="dialogVisible" :tasksinfo="tasksinfo" @close="dialogClose" @opened="openMethods" width="1200px"

weixin_43549003的博客 1760

高通 vs MTK vs 海思:三大平台 ISP 架构横向对比与实战差异分析

随着移动影像能力成为智能终端差异化竞争的核心维度,ISP(Image Signal Processor)架构日益重要。高通、MTK、海思三大 SoC 厂商在 ISP 设计上各具特色,不仅在图像处理链路、模块集成度、算法加速路径等方面存在显著差异,同时也决定了终端厂商在成像质量、调试复杂度与扩展能力上的实际表现。本文将基于真实平台项目经验,横向对比三大主流平台的 ISP 架构关键指标,系统分析其在实际开发过程中的能力边界、工程成本与调优空间,帮助工程师更精准地进行平台选型与优化策略制定。

努力分享一些人工智能、计算机视觉、影像等相关的知识干货! 3926

168张图,万字长文,手把手教你开发vue后台管理系统

.markdown-body { color: rgba(56, 56, 56, 1); font-size: 15px; line-height: 30px; letter-spacing: 2px; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Open...

程序员小明1024 2万+

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

全网最强JavaWeb笔记 | 万字长文爆肝JavaWeb开发——day03_Vue_Element

万字长文爆肝黑马程序员2023最新版JavaWeb教程。这套教程打破常规,不再局限于过时的老套JavaWeb技术,而是与时俱进,运用的都是企业中流行的前沿技术。笔者认真跟着这个教程,再一次认真学习一遍JavaWeb教程,温故而知新,对JavaWeb开发也有了更加深入细致的了解。因此笔者做了全网最全面详细的学习笔记,通篇图文并茂,

qq_45832461的博客 1835

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

Spring Boot+Vue在线教育系统实战:从零构建前后端分离项目

前后端分离架构已成为现代Web开发的主流范式,它将应用逻辑清晰地划分为后端API服务和前端用户界面,通过HTTP协议进行数据交互,从而提升开发效率和系统可维护性。其核心价值在于支持团队并行开发、技术栈灵活选型以及独立的部署与扩展。这种架构尤其适用于像在线教育平台这类功能模块复杂、交互要求高的应用场景。本文聚焦于如何运用Spring Boot与Vue.js两大主流技术栈,手把手实现一个包含用户认证、课程管理、视频播放等核心功能的在线教育系统。文中将详细拆解JWT认证、RESTful API设计以及Vue组件化

weixin_34110749的博客 398

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

SpringBoot+Vue全栈项目实战:从零搭建可交付的超市管理系统

在Java全栈开发中,前后端分离架构已成为现代Web应用的主流模式,其核心原理是通过RESTful API实现前后端解耦与数据交互。这种架构的技术价值在于提升开发效率、便于团队协作并增强系统可维护性。在实际工程实践中,如何将SpringBoot后端与Vue前端高效集成并解决跨域、数据联调等常见问题,是打通全链路的关键。本文聚焦于**SpringBoot**与**Vue**技术栈的工程化整合,通过一个典型的超市管理系统案例,详细拆解从环境配置、项目初始化、数据库设计到前后端联调、打包部署的完整流程,旨在帮助开

weixin_30567225的博客 315

vite+ts+vue3项目初始化 -- eslint+prettier代码格式化

【代码】vite+ts+vue3项目初始化。

weixin_43993776的博客 2388

JavaWeb学习

#前端部分(了解)课程思路、前端要素(Web了解、html、JS、vue、ajax、Element等)传统路线现在课程大纲路线## 前端要素(Web了解、html)HTML语法特点基本标签html标签(span)html标签(a)html标签(video)盒子模型:html标签(div)html标签(表格)html标签(表单)## 前端要素(JS)JS引入方式JS基础语法JS函数JS对象(基础(只关注Array、String、JSON)、BOM、DOM)JS事件监听## 前端要素(Vue)插值表达式Vue常

qq_2634545805的博客 430

使用Element-ui和Vue 实现带数据检测的注册页面

使用element-ui完成注册时的一系列表单验证

gdtown的博客 1063

VUE+elementUi 后台管理系统踩坑日记(el-dialog)

VUE+elementUi 后台管理系统踩坑日记 (el-dialog) el-dialog弹窗组件踩坑,https://element.eleme.cn/2.8/#/zh-CN/component/dialog。 从文档中得知当弹窗打开时是默认body禁止滚动的,但是项目中发现当弹窗打开时候body滚动并没有被禁止。 设置了lock-scroll=true之后依旧无法禁止body滚动。 ...

qq_41915620的博客 2712

elementui表格父子表_vue+element-ui实现主子表

需要实现如下效果一般ERP中,订单数据都分为汇总信息与明细信息,然后在查询的时候一次性从后台查询多条订单json数据,并将汇总信息展示到表格中。但是明细信息也是用户需要关注的,比如用户可能会想知道某个订单里面具体包含哪些商品,下单数量分别是多少。这时候就需要能够点击具体汇总信息行数据的时候,在下方展示出对应的明细数据。实现要点1、主表格绑定 @expand-change 事件2、增加展开列,并在展...

weixin_39611930的博客 4321

Vue3 表单输入案例 以各种设计模式实现

本案例使用 Vue3 和各种设计模式实现表单输入功能。用户可以输入姓名、邮箱、密码和确认密码,完成表单提交后,会弹出一个提示框显示用户输入的表单数据。

qq_21382777的博客 719

vue页面回显数据_vue组件表单数据回显验证及提交的实例代码

最近项目需要到vue开发单页面,所以就研究一下表单数据的回显,验证及提交如何用vue组件的方式实现。代码如下:住户名称:住户类型:{{item.name}}设备名称:{{item.name}}住户大小:请选择{{option.name}}住户留言:点击保存import vue from 'vue'import axios from 'axios';import elementui from 'el...

weixin_29317963的博客 3073

快速创建一个单页面vue页面 引入elelement-ui组件

转自https://element.eleme.cn/#/zh-CN/component/installation。直接从网上链接进文件里,省去下载包(不安全,慎用) https://www.bootcdn.cn/

weixin_45631278的博客 889

vue通用后台管理——用户页面管理功能与form 组件1

vue通用后台管理——用户页面管理功能与form 组件1

qq_51357960的博客 1399
上一篇: PHP 对图片的裁剪,缩略图 方法(后台方法)
下一篇: vue-cli 富文本编辑器vue-quill-editor demo,以及一个页面多个富文本编辑器出现的冲突。
阿……莫西林
博客等级 码龄9年 42粉丝 111原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值