4.1 iHRM人力资源 - 角色管理

iHRM人力资源 - 角色管理

一、搭建页面结构

如下图所示,角色管理模块的内容

主要就是table表格+分页组件

image-20240329211636705

可以将代码放在这里

image-20240329212719747

1.1 页面结构

<template>
  <div class="container">
    <div class="app-container">
      <!--角色管理的内容-->
      <div class="role-operate">
        <el-button size="mini" type="primary">添加角色</el-button>
      </div>
      <!--放置表格组件-->
      <el-table>
        <!--放置4列,align="center"表示居中对齐,"角色"列与"启用"列固定宽度-->
        <el-table-column align="center" width="200" label="角色"></el-table-column>
        <el-table-column align="center" width="200" label="启用"></el-table-column>
        <el-table-column align="center" label="描述"></el-table-column>
        <el-table-column align="center" label="操作"></el-table-column>
      </el-table>

      <!--放置分页组件-->
      <!--使用flex的方式对齐,然后再使用justify="end"表示尾部对齐-->
      <!--align="middle"表示垂直居中-->
      <el-row type="flex" justify="end" style="height: 60px" align="middle">
        <!--放置分页组件,并且在右下方-->
        <!--layout表示分页插件中显示的内容,并且用逗号分隔,"prev,pager,next"分别表示左箭头、数字面板、右箭头-->
        <el-pagination layout="prev,pager,next">

        </el-pagination>
      </el-row>
    </div>
  </div>
</template>
<script>
export default {
  name: 'Role'
}
</script>

<style scoped>

.role-operate {
  padding: 10px
}
</style>

效果图如下所示

image-20240329214451653

1.2 获取角色数据

这一步我们要显示数据,如下图所示

image-20240329214506772

可以按照如下所示的步骤

image-20240329214639583

请求参数

/**
 * 获取角色列表
 */
export function getRoleList(params) {
  return request({
    url: '/sys/role',
    // 这个接口需要param形式的参数,其中param的值就是页码和每页的大小
    params: params // 查询参数
  })
}
  1. 页面初始化时调用函数并赋值给数据
import { getRoleList } from '@/api/role'

export default {
  name: 'Role',
  data() {
    return {
      // 存储分页的数据
      list: []
    }
  },
  created() {
    this.getRoleList()
  },
  methods: {
    async getRoleList() {
      // 将返回结构中的rows内容提取出来
      const { rows } = await getRoleList()
      this.list = rows
    }
  }
}
  1. 绑定表格
<!--放置表格组件-->
<!--:data="list" 绑定数据-->
<el-table :data="list">
  <!--放置4列,align="center"表示居中对齐,"角色"列与"启用"列固定宽度-->
  <el-table-column prop="name" align="center" width="200" label="角色"></el-table-column>
  <el-table-column prop="state" align="center" width="200" label="启用"></el-table-column>
  <el-table-column prop="description" align="center" label="描述"></el-table-column>
  <el-table-column align="center" label="操作"></el-table-column>
</el-table>
  1. 效果图

发现两个问题,

问题1:“启用”列是数字,不是文字

问题2:“操作”列没有操作

所以我们需要自定义一下表格的列

image-20240329215947175

1.3 自定义表格列

接下来我们要展示出如下图所示的结构

image-20240329220604718

element-ui的表格里面可以传入我们的插槽的内容

我们根据数字1或者0展示文字的问题,我们可以使用作用域插槽

下图中,row表示行数据,column表示列数据,我们要行数据row就可以了

image-20240329221010204

如下所示

<!--放置表格组件-->
<!--:data="list" 绑定数据-->
<el-table :data="list">
  <!--放置4列,align="center"表示居中对齐,"角色"列与"启用"列固定宽度-->
  <el-table-column prop="name" align="center" width="200" label="角色"></el-table-column>
  <el-table-column prop="state" align="center" width="200" label="启用">
    <!--插槽内传入我们自定义的列结构-->
    <!--是对象里面有row,所以我们{ row }解构一下数据-->
    <template v-slot="{ row }">
      <!-- 我们可以使用插值语法{{row}}看一下内容内容:{ "id": 1, "name": "系统管理员", "description": "管理整合平台,可以操作企业所有功能", "state": 1 }-->
      <span>{{ row.state === 1 ? '已启用' : row.state === 0 ? '未启用' : '无' }}</span>
    </template>
  </el-table-column>
  <el-table-column prop="description" align="center" label="描述"></el-table-column>
  <el-table-column align="center" label="操作">
    <!--在操作中放置三个按钮-->
    <template>
      <!--type = "text"是将按钮形态转换成链接形态-->
      <el-button size="mini" type="text">分配权限</el-button>
      <el-button size="mini" type="text">编辑</el-button>
      <el-button size="mini" type="text">删除</el-button>
    </template>
  </el-table-column>
</el-table>

效果图如下所示

image-20240329222046706

1.4 分页功能

虽然我们之前写了分页组件,但是我们并没有写真正的页面,现在来完善一下

我们要做的分页形式,如下图所示

image-20240329223013399

流程如下图所示

image-20240329223100200

  1. 绑定分页信息
<!--放置分页组件-->
<!--使用flex的方式对齐,然后再使用justify="end"表示尾部对齐-->
<!--align="middle"表示垂直居中-->
<el-row type="flex" justify="end" style="height: 60px" align="middle">
  <!--放置分页组件,并且在右下方-->
  <!--layout表示分页插件中显示的内容,并且用逗号分隔,"prev,pager,next"分别表示左箭头、数字面板、右箭头-->
  <!--page-size、current-page、total三个是分页数据-->
  <el-pagination
    :page-size="pageParams.pagesize"
    :current-page="pageParams.page"
    :total="pageParams.total"
    layout="prev,pager,next"
  >
  </el-pagination>
</el-row>

分页数据

data() {
  return {
    // 存储分页的数据
    list: [],
    // 将分页信息放到对象中,方便管理
    pageParams: {
      // 当前页默认是1
      page: 1,
      // 每页多少数据
      pagesize: 5,
      // 总数
      total: 0
    }
  }
}
  1. 初始化时请求第一页
created() {
  this.getRoleList()
},
methods: {
  async getRoleList() {
    // 将返回结构中的rows内容提取出来,也提取出total总数字段
    const { rows, total } = await getRoleList(this.pageParams)
    this.list = rows
    this.pageParams.total = total
  }
}
  1. 切换分页时请求对应数据

分页组件增加 @current-change事件,并调用changePage方法

<!--放置分页组件,并且在右下方-->
<!--layout表示分页插件中显示的内容,并且用逗号分隔,"prev,pager,next"分别表示左箭头、数字面板、右箭头-->
<!--page-size、current-page、total三个是分页数据-->
<!--事件@current-change触发时,会给我们传一个是哪一页的参数-->
<el-pagination
  :page-size="pageParams.pagesize"
  :current-page="pageParams.page"
  :total="pageParams.total"
  @current-change="changePage"
  layout="prev,pager,next"
>
</el-pagination>
// 会给我们传一个是哪一页的参数,在这里就是newPage
changePage(newPage) {
  this.pageParams.page = newPage
  this.getRoleList()
}

二、添加角色

效果及流程如下图所示

image-20240331145354012

2.1 角色弹出层

按钮

<div class="role-operate">
  <!--添加点击事件-->
  <el-button @click="showDialog=true" size="mini" type="primary">添加角色</el-button>
</div>

数据

data() {
  return {
    // 控制添加弹层
    showDialog: false
      ........
  }
},

弹出层

<!--弹层-->
<!--sync的目的:当我们点击×号的时候,能把showDialog值改为false-->
<el-dialog width="500px" title="新增角色" :visible.sync="showDialog">
  <el-form label-width="120px">
    <el-form-item label="角色名称">
      <el-input style="width: 300px" size="mini"></el-input>
    </el-form-item>

    <el-form-item label="启用">
      <!--开关-->
      <el-switch size="mini"></el-switch>
    </el-form-item>

    <el-form-item label="角色描述">
      <!--文本域,行数为3行-->
      <el-input type="textarea" :rows="3" style="width: 300px" size="mini"></el-input>
    </el-form-item>

    <el-form-item>
      <!--为了让按钮居中,我们可以采用row和col组件来实现-->
      <el-row type="flex" justify="center">
        <el-col :span="12">
          <el-button type="primary" size="mini">确定</el-button>
          <el-button size="mini">取消</el-button>
        </el-col>
      </el-row>
    </el-form-item>
  </el-form>
</el-dialog>

效果图

image-20240331151910286

2.2 表单校验

实现如下图所示的内容

image-20240331152713279

绑定属性及校验规则

// 角色表单
roleForm: {
  // 名称
  name: '',
  // 描述
  description: '',
  // 是否启用,默认未启用状态
  state: 0
},
rules: {
  name: [{ required: true, message: '角色名称不能为空', trigger: 'blur' }],
  description: [{ required: true, message: '角色描述不能为空', trigger: 'blur' }]
}
    <!--弹层-->
    <!--sync的目的:当我们点击×号的时候,能把showDialog值改为false-->
    <el-dialog width="500px" title="新增角色" :visible.sync="showDialog">
      <el-form ref="roleForm" :model="roleForm" label-width="120px" :rules="rules">
        <el-form-item prop="name" label="角色名称">
          <el-input v-model="roleForm.name" style="width: 300px" size="mini"></el-input>
        </el-form-item>
        <el-form-item prop="state" label="启用">
          <!--开关,此处不需要校验-->
          <!--开和关的默认值是true和false,但是我们需要的是1或者0,所以我们自定义一下 active-value="1" inactive-value="0",表示开为1,关为0-->
          <el-switch v-model="roleForm.state" :active-value="1" :inactive-value="0" size="mini"></el-switch>
        </el-form-item>
        <el-form-item prop="description" label="角色描述">
          <!--文本域,行数为3行-->
          <el-input v-model="roleForm.description" type="textarea" :rows="3" style="width: 300px" size="mini"></el-input>
        </el-form-item>
        <el-form-item>
          <!--为了让按钮居中,我们可以采用row和col组件来实现-->
          <el-row type="flex" justify="center">
            <el-col :span="12">
              <el-button type="primary" size="mini">确定</el-button>
              <el-button size="mini">取消</el-button>
            </el-col>
          </el-row>
        </el-form-item>
      </el-form>
    </el-dialog>

效果图

image-20240331154352893

2.3 确认取消

流程如下所示

image-20240331154535693

API请求

/**
 * 新增角色
 */
export function addRole(data) {
  return request({
    url: '/sys/role',
    // 这个接口需要param形式的参数,其中param的值就是页码和每页的大小
    method: 'post',
    data: data
  })
}

按钮

<el-button @click="btnOK" type="primary" size="mini">确定</el-button>
<el-button @click="btnCancel" size="mini">取消</el-button>

方法

// 确定按钮
btnOK() {
  this.$refs.roleForm.validate(async isOK => {
    if (isOK) {
      await addRole(this.roleForm)
      this.$message.success('新增角色成功')
      // 重新获取数据
      this.getRoleList()
      this.btnCancel()
    }
  })
},
// 取消按钮
btnCancel() {
  // 重置表单
  this.$refs.roleForm.resetFields()
  // 关闭弹层
  this.showDialog = false
}

但是现在有一个问题

我们在使用 this.$refs.roleForm.resetFields()重置表单的时候,并没有把roleForm.state属性值重置为0,原因是我们表单中的state并没用使用prop绑定到roleForm.state值上

所以我们仍然需要在“启用”上加上prop字段

简单的说,如果我们需要使用resetFields()方法重置表单的时候,也需要在el-form-item标签上添加prop属性

<el-form-item prop="state" label="启用">
  <!--开关,此处不需要校验-->
  <!--开和关的默认值是true和false,但是我们需要的是1或者0,所以我们自定义一下 active-value="1" inactive-value="0",表示开为1,关为0-->
  <el-switch v-model="roleForm.state" :active-value="1" :inactive-value="0" size="mini"></el-switch>
</el-form-item>

并且我们发现点击叉号关闭弹层后不会将表单重置

因为visible.sync只会把showDialog属性值变成false

所以我们在标签el-dialog上添加@close事件

<el-dialog @close="btnCancel" width="500px" title="新增角色" :visible.sync="showDialog">

三、行内编辑

3.1 思路分析

如下图所示,不需要弹层进行编辑,而是直接在此数据行修改数据

image-20240331165427567

并且还能实现多行同时编辑

image-20240331165533392

如下四功能

  1. 要实现表格的行内表单,也就是说要把表单嵌入在表格的列里面
  2. 可以多行同时编辑
  3. 确定是保存数据
  4. 当我们修改完数据后,突然不想修改,仍能保持原数据

image-20240331170308174

实现思路

  1. 首先在行数据里面定义一个"编辑"的标记。

    也就是说看哪一行进入了编辑状态

  2. 点击某一行的“编辑”后,此时的“编辑”状态就会发生变化

  3. 在列里面利用自定义插槽自定义我们的编辑表单

image-20240331170730868

3.2 行内编辑

  1. 行数据定义编辑标记
async getRoleList() {
  // 将返回结构中的rows内容提取出来,也提取出total总数字段
  const { rows, total } = await getRoleList(this.pageParams)
  this.list = rows
  this.pageParams.total = total
  // 针对每一行数据添加一个编辑标记,为了实现行内编辑
  this.list.formEach(item => {
    // 添加一个新字段isEdit,并且值为false
    item.isEdit = false
  })
},

效果如下图所示

image-20240331171232095

  1. 点击行编辑,标记状态

也就是让isEdit字段的值为true

按钮

<!--在操作中放置三个按钮-->
<!--是对象里面有row,所以我们{ row }解构一下数据-->
<template v-slot="{ row }">
  <!--type = "text"是将按钮形态转换成链接形态-->
  <el-button @click="btnEditRow(row)" size="mini" type="text">编辑</el-button>
    ......
</template>

执行方法btnEditRow

btnEditRow(row) {
  // 改变行的编辑状态
  row.isEdit = true
}
  1. 插槽根据标记渲染表单
      <!--放置表格组件-->
      <!--:data="list" 绑定数据-->
      <el-table :data="list">
        <!--放置4列,align="center"表示居中对齐,"角色"列与"启用"列固定宽度-->
        <el-table-column prop="name" align="center" width="200" label="角色">
          <!--行内编辑时的表单-->
          <!--利用插槽解构出row-->
          <template v-slot="{ row }">
            <!--条件判断,当isEdit为true时,就展示input框-->
            <el-input size="mini" v-if="row.isEdit"></el-input>
            <span v-else>{{ row.name }}</span>
          </template>
        </el-table-column>
        <el-table-column prop="state" align="center" width="200" label="启用">
          <!--插槽内传入我们自定义的列结构-->
          <!--是对象里面有row,所以我们{ row }解构一下数据-->
          <template v-slot="{ row }">
            <el-switch v-if="row.isEdit" size="mini"></el-switch>
            <!-- 我们可以使用插值语法{{row}}看一下内容内容:{ "id": 1, "name": "系统管理员", "description": "管理整合平台,可以操作企业所有功能", "state": 1 }-->
            <span v-else>{{ row.state === 1 ? '已启用' : row.state === 0 ? '未启用' : '无' }}</span>
          </template>
        </el-table-column>
        <el-table-column prop="description" align="center" label="描述">
          <template v-slot="{ row }">
            <el-input v-if="row.isEdit" type="textarea" size="mini"></el-input>
            <span v-else>{{ row.description }}</span>
          </template>
        </el-table-column>
        <el-table-column align="center" label="操作">
          <!--在操作中放置三个按钮-->
          <!--是对象里面有row,所以我们{ row }解构一下数据-->
          <template v-slot="{ row }">
            <!--编辑状态-->
            <template v-if="row.isEdit">
              <el-button type="primary" size="mini">确定</el-button>
              <el-button size="mini">取消</el-button>
            </template>
            <!--非编辑状态-->
            <template v-else>
              <!--下面三个标签在编辑情况下是不展示的-->
              <!--type = "text"是将按钮形态转换成链接形态-->
              <el-button size="mini" type="text">分配权限</el-button>
              <el-button @click="btnEditRow(row)" size="mini" type="text">编辑</el-button>
              <el-button size="mini" type="text">删除</el-button>
            </template>
          </template>
        </el-table-column>
      </el-table>

修改bug

我们点击“编辑”,发现并不管用,原因如下

async getRoleList() {
  // 将返回结构中的rows内容提取出来,也提取出total总数字段
  const { rows, total } = await getRoleList(this.pageParams)
  this.list = rows
  this.pageParams.total = total
  // 针对每一行数据添加一个编辑标记,为了实现行内编辑
  this.list.forEach(item => {
    // 添加一个新字段isEdit,并且值为false
    // item.isEdit = false
    // 数据响应式的问题:数据变化,视图更新 是针对已经有的属性
    // 添加的动态属性,是不具备响应式特点,因为并没有监控到isEdit字段值的变化,所以我们点击“编辑”后,并不会出现输入框
    // 所以我们应该像下面一样添加属性
    // this.$set(目标对象,属性名称,初始值)可以针对目标对象添加的属性添加响应式
    this.$set(item, 'isEdit', false)
    // 这样的话就会触发视图的更新
  })
}

效果图

当时我们发现修改时,没有数据,我们接下来就写上

image-20240331180404117

3.3 行内数据缓存

3.3.1 分析

我们要实现点击“编辑”时,数据能够回显上去

我们编辑的数据并不是真实的列表数据,而是行内数据里面的editRow的缓存数据

image-20240331180647330

这样就确保了原来的数据不受任何的影响,所以我们需要在每一行里加一个“editRow”对象

不仅初始化的时候要更新editRow,而且我们每次点击“编辑”的时候,都要重新更新editRow缓存中内容

image-20240331181015004

3.3.2 实现

  1. 初始化时缓存数据
async getRoleList() {
  // 将返回结构中的rows内容提取出来,也提取出total总数字段
  const { rows, total } = await getRoleList(this.pageParams)
  this.list = rows
  this.pageParams.total = total
  // 针对每一行数据添加一个编辑标记,为了实现行内编辑
  this.list.forEach(item => {
    // 添加一个新字段isEdit,并且值为false
    // item.isEdit = false
    // 数据响应式的问题:数据变化,视图更新 是针对已经有的属性
    // 添加的动态属性,是不具备响应式特点,因为并没有监控到isEdit字段值的变化,所以我们点击“编辑”后,并不会出现输入框
    // 所以我们应该像下面一样添加属性
    // this.$set(目标对象,属性名称,初始值)可以针对目标对象添加的属性添加响应式
    // 这样的话就会触发视图的更新
    this.$set(item, 'isEdit', false)
    // 行内数据缓存
    this.$set(item, 'editRow', { name: item.name, state: item.state, description: item.description })
  })
  1. 将数据绑定到编辑形态上的表单

    其实就在column标签中的编辑形态下的input框加一个v-model双向绑定

<!--放置4列,align="center"表示居中对齐,"角色"列与"启用"列固定宽度-->
<el-table-column prop="name" align="center" width="200" label="角色">
  <!--行内编辑时的表单-->
  <!--利用插槽解构出row-->
  <template v-slot="{ row }">
    <!--条件判断,当isEdit为true时,就展示input框-->
    <el-input v-model="row.editRow.name" size="mini" v-if="row.isEdit"></el-input>
    <span v-else>{{ row.name }}</span>
  </template>
</el-table-column>
<el-table-column prop="state" align="center" width="200" label="启用">
  <!--插槽内传入我们自定义的列结构-->
  <!--是对象里面有row,所以我们{ row }解构一下数据-->
  <template v-slot="{ row }">
    <el-switch v-model="row.editRow.state" :active-value="1" :inactive-value="0" v-if="row.isEdit" size="mini"></el-switch>
    <!-- 我们可以使用插值语法{{row}}看一下内容内容:{ "id": 1, "name": "系统管理员", "description": "管理整合平台,可以操作企业所有功能", "state": 1 }-->
    <span v-else>{{ row.state === 1 ? '已启用' : row.state === 0 ? '未启用' : '无' }}</span>
  </template>
</el-table-column>
<el-table-column prop="description" align="center" label="描述">
  <template v-slot="{ row }">
    <el-input v-model="row.editRow.description" v-if="row.isEdit" type="textarea" size="mini"></el-input>
    <span v-else>{{ row.description }}</span>
  </template>
</el-table-column>
  1. 点击“编辑”按钮的时候,更新我们的缓存数据
btnEditRow(row) {
  // 改变行的编辑状态
  row.isEdit = true
  // 更新缓存数据
  row.editRow.name = row.name
  row.editRow.state = row.state
  row.editRow.description = row.description
}

3.4 确定与取消按钮

我们在表格里面没法使用form表单,所以我们就需要手动检查必填项

image-20240331214906606

api请求

/**
 * 修改角色
 */
export function updateRole(data) {
  return request({
    url: `/sys/role/${data.id}`,
    // 这个接口需要param形式的参数,其中param的值就是页码和每页的大小
    method: 'put',
    data: data
  })
}

确定与取消按钮

<!--编辑状态-->
<template v-if="row.isEdit">
  <el-button @click="btnEditOK(row)" type="primary" size="mini">确定</el-button>
  <!--退出编辑模式-->
  <el-button @click="row.isEdit = false" size="mini">取消</el-button>
</template>

方法

// 编辑功能
async btnEditOK(row) {
  // 我们要发送请求的数据其实是row.editRow
  // 检查必填项
  if (row.editRow.name && row.editRow.description) {
    // 说明这两项已经填写了
    // ...row.editRow表示将row.editRow里面的字段拷贝了一份
    // id表示新增的字段, row.id表示将其值赋值给id字段
    await updateRole({ ...row.editRow, id: row.id })
    // 更新成功
    this.$message.success('更新角色成功')
    // 更新显示数据、退出编辑状态
    // row.name = row.editRow.name // 这个地方虽然有报错,但是是eslint解析的误判
    // Object.assign(target,source) 我们可以把来源的数据赋值给target中的数据
    // 下面的值也包括退出编辑模式
    Object.assign(row, {
      name: row.editRow.name,
      description: row.editRow.description,
      state: row.editRow.state,
      isEdit: false
    })
    // 还有一个写法就是使用延展运算符   Object.assign(row, { ...row.editRow,isEdit: false })
  } else {
    this.$message.warning('角色和描述不能为空')
  }
}

四、删除角色

点击删除的时候,会出现一个气泡框

image-20240331220903490

流程如下所示

删除的时候要判断是否删除的是最后一个数据

image-20240331221239696

api请求

/**
 * 删除角色
 */
export function delRole(id) {
  return request({
    url: `/sys/role/${id}`,
    // 这个接口需要param形式的参数,其中param的值就是页码和每页的大小
    method: 'delete'
  })
}

按钮

<!--非编辑状态-->
<template v-else>
  <!--type = "text"是将按钮形态转换成链接形态-->
    ..........
  <!--点击确认后会触发@onConfirm事件-->
  <el-popconfirm @onConfirm="confirmDel(row.id)" title="您确定要删除吗?">
    <el-button slot="reference" style="margin-left: 10px" size="mini" type="text">删除</el-button>
  </el-popconfirm>
</template>

方法

// 删除角色
async confirmDel(id) {
  await delRole(id)
  this.$message.success('删除角色成功')
  // 判断删除的是不是数据中最后一个
  if (this.list.length === 1) {
    // 说明此时删除的数据是最后一个数据
    this.pageParams.page = this.pageParams.page - 1
  }
  // 重新加载数据
  this.getRoleList()
}
  • 28
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
手把手视频详细讲解项目开发全过程,需要的小伙伴自行百度网盘下载,链接见附件,永久有效。 项目介绍: iHRM是一款基于SaaS平台的人力资源管理系统, 企业通过该系统可以完成员工管理、审批管理、考勤管理、社保公积金管理、薪资管理等功能,为企业的人力资源管理提供一站式解决方案。 掌握的核心能力:   1、能够了解SaaS的基本概念   2、掌握Activiti7工作流引擎的使用   3、能够掌握商用权限方案的设计   4、能够使用JasperReport生成报表。   5、能够使用PowerDesigner构建数据库模型   6、了解SAAS-HRM中权限控制   7、理解前端权限控制思路   8、熟练构造Chart图形报表 解决方法:   1、Spring全家桶解决方案|   2、SPA工程构建解决方案|   3、Saas系统数据库设计方案|   4、统一会话管理的解决方案|   5、企业级报表解决方案|   6、系统认证授权的解决方案|   7、云存储解决方案|   8、RBAC权限设计方案|   9、刷脸登录解决方案|   10、自定义代码生成器|   11、Activiti工作流开发| 涵盖知识点:   1.结合Activiti7工作流引擎的应用教程。   2.基于Shiro+Redis的分布式session解决方案。   3.可商用的权限设计方案(提供菜单,按钮,超链接,API粒度的权限控制)。   4.完整的代码生成器教程。   5.采用JasperReport完成企业级PDF报表生成。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我爱布朗熊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值