likes
comments
collection
share

Vue3电影中后台开发纪实(三):数据展示

作者站长头像
站长
· 阅读数 67

@拿到热映数据

  • 使用POSTMAN提前向后台插入电影数据

配置全局代理

vite.config.js

  // 配置前端服务地址和端口
  server: {
    host: "0.0.0.0",
    port: 5173,

    // 是否开启 https
    https: false,

    // 让开发服务器帮我们做代理
    proxy: {
      // http://localhost:5173/api
      "/api": {
        target: "http://localhost:8173", //API服务地址
        changeOrigin: true, //开启跨域
        rewrite: (path) => path.replace(/^\/api/, ""),
      },
    },
  },

配置网络应用层

src/api/movieApi.js

import axios from "axios";
import { doGet } from "./service/crud";

/* 获取正在热映列表 */
export async function getPlayings() {
  // localhost:5173/api/film/0 => vite会将该地址代理到localhost:8173/film/0
  const {arr:films} = await doGet(`/film/0`);
  return films;
}

组件挂载时获取数据

src/views/film/Playing.vue

import { getPlayings } from "@api/movieApi";

/* 组件挂载完毕后发起AJAX请求 */
onMounted(async () => {
  const films = await getPlayings();
  console.log("films=", films);
});

@表格展示数据

分页加载

src/views/film/Playing.vue

/* 完整电影列表 */
const tableData = ref([]);

/* 要显示的分页数据 */
const currentPage = ref(1);
const computedData = computed(() =>
  tableData.value.slice((currentPage.value - 1) * 10, currentPage.value * 10)
);

/* 组件挂载完毕后发起AJAX请求 */
onMounted(async () => {
  const films = await getPlayings();
  console.log("films=", films);

  tableData.value = films;
});

表格列展示数据

<el-table
  :data="computedData"
  stripe
  style="width: 100%"
  :default-sort="{ prop: 'date', order: 'ascending' }"
  @selection-change="handleSelectionChange"
>
  <!-- 多选显示栏 -->
  <el-table-column type="selection" width="40" />

  <!-- fixed固定 sortable字段可排序 label=当前列标题 width当前列像素宽度 -->
  <el-table-column sortable fixed prop="filmId" label="id" width="100" />

  <!-- 片名 -->
  <el-table-column sortable prop="name" label="片名" width="180" />

  <!-- 海报 -->
  <el-table-column prop="poster" label="海报" width="60" >
    <template #default="{row:{poster}}">
      <div style="display: flex; align-items: center">
        <el-image :src="poster" />
      </div>
    </template>
  </el-table-column>

  <!-- 主演 -->
  <el-table-column
    sortable
    prop="actors"
    label="主演"
    :formatter="formatActors"
    width="200"
  />

  <!-- 国家 -->
  <el-table-column sortable prop="nation" label="国家" width="150" />

  <!-- 类型 -->
  <el-table-column sortable prop="category" label="类型" width="150" />

  <!-- 片长 -->
  <el-table-column sortable prop="runtime" label="片长" width="100" />

  <!-- 评分 -->
  <el-table-column sortable prop="grade" label="评分" width="100" />

  <!-- 首映日期 -->
  <el-table-column
    sortable
    prop="premiereAt"
    label="首映日期"
    :formatter="formatPremierAt"
    width="150"
  />

  <!-- fixed="right"右侧固定 -->
  <el-table-column fixed="right" label="操作" width="90">
    <!-- 覆盖为小号圆形的编辑按钮与删除按钮 -->
    <template #default>
      <el-button type="primary" :icon="Edit" circle size="small" />
      <el-button type="danger" :icon="Delete" circle size="small" />
    </template>
  </el-table-column>
</el-table>

数据格式化

/* 数据格式化函数 */
const formatPremierAt = (row, column, cellValue, index) => {
  // console.log("row", row);//当前行数据
  // console.log("column", column);//当前列信息
  // console.log("cellValue", cellValue);//当前要格式化的单元格数据
  // console.log("index", index);//当前行行号

  return new Date(cellValue * 1000).toLocaleDateString().replaceAll("/", "-");
};
const formatActors = (row, column, cellValue, index) => {
  return (
    cellValue
      .map((actor) => actor.name)
      .slice(0, 3)
      .join(",") + "等"
  );
};

展示电影海报

  <!-- 海报 -->
  <el-table-column prop="poster" label="海报" width="60" >
    <!-- <template #default="scope"> -->
    <template #default="{row:{poster}}">
      <div style="display: flex; align-items: center">
        <!-- 这里我们通过一个简单的测试发现scope.row.poster即要显示的海报数据 -->
        <!-- <el-image :src="showScope(scope)" /> -->
        <el-image :src="poster" />
      </div>
    </template>
  </el-table-column>

@跳转详情页

定义详情页路由

src/router/index.js

{
  // 规定电影id为24个数字或小写字母
  path: "/film/:id(\\d+)",
  name: "detail",
  meta: { hideTabbar: true },
  component: () => import("../views/DetailView.vue"),
},

跳转详情页

src/views/Playing.vue

  <!-- 右侧固定的操作按钮区 -->
  <el-table-column fixed="right" label="操作" width="90">

    <!-- action按钮区作用域插槽提供的数据中含有当前行信息row -->
    <!-- <template #default="scope"> -->

    <!-- 可以通过简单的测试查看一下作用域插槽中携带的数据 -->
    <!-- <el-button @click="showScope(scrope)"/> -->

    <!-- 从作用域插槽数据中解构出当前行id -->
    <template #default="{ row: { _id } }">

      <!-- 点击Edit按钮 携带id跳转详情页 -->
      <el-button @click="$router.push(`/film/${_id}`)" type="primary" :icon="Edit" circle size="small" />
      <el-button type="danger" :icon="Delete" circle size="small" />

    </template>
  </el-table-column>

@详情页数据展示

获取详情数据

src/views/Detail.vue

import { onMounted } from "vue";
import { useRoute } from "vue-router";
import { getDetail } from "@api/movieApi";

/* 获取影片详情 */
onMounted(async () => {
  const detail = await getDetail(route.params.id);
  console.log("detail=", detail);
});

添加Loading效果

<template>
  <el-card v-loading="loading">
      正文内容...
  </el-card>
</template>
/* 获取影片详情 */
onMounted(async () => {
  loading.value = true;

  const detail = await getDetail(route.params.id);
  console.log("detail=", detail);
  
  /* 将detail中的数据同步到form中 表单中自动同步数据 */
  // ...

  setTimeout(() => {
    loading.value = false;
  }, 500);
});

定义表格数据

const form = reactive({});

/* 获取影片详情 */
onMounted(async () => {
  loading.value = true;
  const detail = await getDetail(route.params.id);
  console.log("detail=", detail);

  /* 将detail中的数据同步到form中 表单中自动同步数据 */
  Object.assign(form, detail, {
    premiereAt: detail.premiereAt * 1000,

    // 影片类型 表单复选 应双向绑定一个数组
    category: detail.category.split("|"),

    // 重构actcors数据
    actors: detail.actors.map(({ name, role, avatarAddress }) => ({
      name: `${name}-${role}`,
      url: avatarAddress,
    })),
  });

  setTimeout(() => {
    loading.value = false;
  }, 500);
});

表格展示数据

<template>
  <el-card v-loading="loading">
    <template #header>
      <div class="card-header">
        <span>影片详情</span>
        <!-- <el-button class="button" text>Operation button</el-button> -->
      </div>
    </template>

    <!-- 详情表单 -->
    <!-- form没有数据时不渲染form -->
    <el-form v-if="form[`name`]" :model="form" label-width="120px">
      <!-- 片名关联form.name -->
      <el-form-item label="片名">
        <el-input v-model="form.name" />
      </el-form-item>

      <!-- 片长关联form.runtime -->
      <el-form-item label="片长">
        <el-col :span="7">
          <el-input v-model="form.runtime" type="number" />
        </el-col>
      </el-form-item>

      <!-- 评分关联form.grade -->
      <el-form-item label="评分">
        <el-col :span="7">
          <el-input v-model="form.grade" />
        </el-col>
      </el-form-item>

      <!-- 影片类型关联form.filmType.name -->
      <!-- filmType?.name 如果filmType不为null/undeined 就继续读取filmType?.name 否则直接返回null/undeined -->
      <el-form-item label="影片类型">
        <el-select
          v-model="form.filmType.name"
          placeholder="please select your zone"
        >
          <el-option label="2D" value="2D" />
          <el-option label="3D" value="3D" />
          <el-option label="4D" value="4D" />
        </el-select>
      </el-form-item>

      <!-- 影片类型关联form.premiereAt -->
      <el-form-item label="首映日期">
        <el-col :span="8">
          <el-date-picker
            v-model="form.premiereAt"
            type="date"
            placeholder="Pick a date"
            style="width: 100%"
          />
        </el-col>
      </el-form-item>

      <!-- 在映关联form.isPresale -->
      <el-form-item label="在映">
        <el-switch v-model="form.isPresale" />
      </el-form-item>

      <!-- 影片类型关联form.category -->
      <el-form-item label="影片类型">
        <el-checkbox-group v-model="form.category">
          <el-checkbox label="爱情" name="category" />
          <el-checkbox label="动作" name="category" />
          <el-checkbox label="科幻" name="category" />
          <el-checkbox label="历史" name="category" />
          <el-checkbox label="悬疑" name="category" />
          <el-checkbox label="喜剧" name="category" />
          <el-checkbox label="战争" name="category" />
          <el-checkbox label="剧情" name="category" />
          <el-checkbox label="犯罪" name="category" />
          <el-checkbox label="纪录片" name="category" />
        </el-checkbox-group>
      </el-form-item>

      <!-- 国家关联form.nation -->
      <el-form-item label="国家">
        <el-radio-group v-model="form.nation">
          <el-radio label="中国大陆" />
          <el-radio label="欧美" />
          <el-radio label="日韩" />
          <el-radio label="其它" />
        </el-radio-group>
      </el-form-item>

      <!-- 演职人员关联form.actors -->
      <!-- 
      :on-preview="handlePreview"
      :on-remove="handleRemove"
       -->
      <el-form-item label="演职人员">
        <el-upload
          v-model:file-list="form.actors"
          class="upload-demo"
          list-type="picture-card"
          action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
        >
          <el-icon><Plus /></el-icon>
        </el-upload>
      </el-form-item>

      <!-- 海报关联form.poster -->
      <el-form-item label="海报">
        <el-upload
          v-model:file-list="form.poster"
          action="https://run.mocky.io/v3/9d059bf9-4660-45f2-925d-ce80ad6c4d15"
          list-type="picture-card"
        >
          <el-icon><Plus /></el-icon>
        </el-upload>
      </el-form-item>

      <!-- 剧情摘要form.synopsis -->
      <el-form-item label="剧情摘要">
        <el-input v-model="form.synopsis" autosize type="textarea" />
      </el-form-item>

      <!-- 提交与重置 -->
      <el-form-item>
        <el-button class="opBtn" type="primary" @click="onSubmit">更新</el-button>
        <el-button class="opBtn">重置</el-button>
      </el-form-item>
    </el-form>
  </el-card>
</template>

转载自:https://juejin.cn/post/7169131209983787039
评论
请登录