JVS低代码开发中,如何创建自定义前端页面并接入到现有系统中,从创建到接入的全攻略

在当前快速变化的数字化时代,企业对系统定制化的需求越来越多。传统的方式就是从基础的代码编写到复杂的业务逻辑去实现。但是,一旦业务需求发生变更,修改和迭代的过程就更加繁琐。

在JVS低代码开发中,它可以通过可视化配置和少量代码快速实现,让前端页面定制变得简单灵活。

今天我以这个系统为例,分享它如何从零开始创建自定义前端页面并接入现有系统的完整流程。

第一步:创建逻辑标识接口

  1. 登录后台管理系统
  2. 创建以事件触发的逻辑并配置逻辑
  3. 创建源码标识,例如:/demo/student/count
  4. 请求逻辑接口:/rule/openapi/appIdentificationname/demo/student/count

这一步的目的是创建业务逻辑接口,用于前端页面调用获取数据或执行业务操作。

复制代码
# 测试请求
curl 'http://localhost:9999/rule/openapi/appIdentificationname/demo/student/count' \
  -H 'Authorization: Bearer Vk_tLc1nYRwqm8ksuJQ30tUrwlzauXQRtZHrammOyqkxFunTDlNV8oE83qpYpPBZcPu5kwHzlpuJjlnChZmD2r_Zi1doywRIzPUOIq6IUpYFv1qwfMrsHrrYLuDVyBkB' \
  -H 'MODE: DEV' 
 

#返回数据
{"code":0,"msg":"success","data":2,"timestamp":1761293844018}

第二步:创建前端项目

可以直接下载示例项目进行复制,直接运行即可。下载

复制代码
npm install

npm run dev

Token配置(axios.js)

复制代码
// 本地调试固定Token,与登录用户的 token保持一致进行调试, 部署前请将此处注释
config.headers["Authorization"] = 'Bearer Vk_tLc1nYRwqm8ksuJQ30tUrwlzauXQRtZHrammOyqkxFunTDlNV8oE83qpYpPBZcPu5kwHzlpuJjlnChZmD2r_Zi1doywRIzPUOIq6IUpYFv1qwfMrsHrrYLuDVyBkB';
// 本地添加调试模式,部署后自动获取
config.headers["MODE"] = 'DEV';

环境要求

  • Node.js 16.0.0+

项目初始化

复制代码
# 创建项目目录
mkdir appIdentificationdemo
cd appIdentificationdemo

# 初始化项目
npm init -y

# 安装必要依赖
npm install vue@^2.6.10 vue-router@^3.1.3 axios@^0.19.0 element-ui@^2.13.0
npm install -D @vue/cli-service@^3.11.0 sass@^1.87.0 sass-loader@^8.0.0

项目结构示例

复制代码
appIdentificationdemo/
├── public/
│   └── index.html
├── src/
│   ├── router/
│   │   ├── axios.js
│   │   ├── router.js
│   │   └── views/
│   │       └── index.js
│   ├── views/
│   │   ├── api/
│   │   │   └── index.js
│   │   └── demo/
│   │       └── index.vue
│   ├── App.vue
│   └── main.js
├── vue.config.js
└── package.json

第三步:开发页面

1. 配置请求拦截器 (src/router/axios.js)

复制代码
import axios from 'axios'

// 设置超时时间
axios.defaults.timeout = 30000;

// HTTP request拦截器
axios.interceptors.request.use(
    config => {
        // 本地开发配置临时Token 可以直接连接部署环境进行调试查看
        config.headers["Authorization"] = 'Bearer [临时token]';
        config.headers["MODE"] = 'DEV';
        return config;
    },
    error => {
        return Promise.reject(error);
    }
);

// HTTP response拦截器
axios.interceptors.response.use(
    res => {
        return res;
    },
    error => {
        return Promise.reject(new Error(error));
    }
);

export default axios;

2. 创建API接口 (src/views/api/index.js)

复制代码
import request from "@/router/axios"

// 分页查询数据
export const queryPage = (modelIdentification,) => {
    return request({
        url: `/jvs-design/app/identification/use/dynamic/data/query/page/${modelIdentification}`,
        method: "post",
        data: data
    })
}

// 查询单条数据
export const getSingle = (modelIdentification,) => {
    return request({
        url: `/jvs-design/app/identification/use/dynamic/data/query/single/${modelIdentification}/${dataId}`,
        method: "get"
    })
}

// 新增数据
export const addSingle = (modelIdentification,) => {
    return request({
        url: `/jvs-design/app/identification/use/dynamic/data/save/${modelIdentification}`,
        method: "post",
        data: data
    })
}

// 修改数据
export const editSingle = (modelIdentification, data,) => {
    return request({
        url: `/jvs-design/app/identification/use/dynamic/data/update/${modelIdentification}/${dataId}`,
        method: "post",
        data: data
    })
}

// 删除数据
export const deleteData = (modelIdentification,) => {
    return request({
        url: `/jvs-design/app/identification/use/dynamic/data/delete/${modelIdentification}/${dataId}`,
        method: "delete"
    })
}

// 获取业务逻辑数据
export const getUserCount = () => {
    return request({
        url: `/rule/openapi/appIdentificationname/demo/student/count`,
        method: "get"
    })
}

3. 创建页面组件 (src/views/demo/index.vue)

复制代码
<template>
  <div class="demo-list">
    <div class="top-bar">
      <el-button type="primary" @click="addEditViewRow(null, 'add')">新增</el-button>
      <div>
        <span style="font-size: 12px;">调用逻辑示例</span>
        <el-tag style="margin-left: 10px;">当前用户总人数: {{userTotal}}</el-tag>
      </div>
    </div>
    <el-table :data="tableData" style="width:">
      <el-table-column prop="name" label="姓名"></el-table-column>
      <el-table-column prop="age" label="年龄"></el-table-column>
      <el-table-column prop="id" label="学号"></el-table-column>
      <el-table-column label="操作" width="140">
        <template slot-scope="scope">
          <el-button type="text" size="small" @click="addEditViewRow(scope.row, 'edit')">编辑</el-button>
          <el-button type="text" size="small" @click="addEditViewRow(scope.row, 'view')">查看</el-button>
          <el-button type="text" size="small" style="color: #F56C6C;" @click="deleteRow(scope.row)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    <!-- 分页组件和表单弹窗 -->
  </div>
</template>

<script>
  import {queryPage, getSingle, addSingle, editSingle, deleteData, getUserCount} from '@/views/api/index'

  export default {
    data() {
      return {
        routeQuery: {
          dataModelId: 'student_demo'
        },
        page: {
          total: 0,
          currentPage: 1,
          pageSize: 20,
        },
        tableData: [],
        userTotal: 0,
      }
    },
    created() {
      this.getListHandle()
      getUserCount().then(res => {
        if (res.data && res.data.code == 0) {
          this.userTotal = res.data.data
        }
      })
    },
    methods: {
      getListHandle() {
        let query = {
          current: this.page.currentPage,
          size: this.page.pageSize
        }
        queryPage(this.routeQuery.dataModelId, query).then(res => {
          if (res.data && res.data.code == 0) {
            this.page.total = res.data.data.total
            this.page.currentPage = res.data.data.current
            this.tableData = res.data.data.records
          }
        })
      },
      addEditViewRow(row,) {
        // 实现新增、编辑、查看逻辑
      },
      deleteRow(row) {
        // 实现删除逻辑
      }
    }
  }</script>

4. 配置路由 (src/router/views/index.js)

一个项目可以配置 N个路由,对应多个应用

复制代码
let base = process.env.NODE_ENV === 'production' ? '/app/source/appIdentificationdemo' : ''

export default [
    {
        path: base + '/list',
        name: '应用详情',
        component: () => import('@/views/demo/index'),
        meta: {
            keepAlive: true,
            isTab: false,
            isAuth: false
        }
    }
]

5. 配置构建设置 (vue.config.js)

复制代码
const url = "http://gateway:10000" // 网关地址

// 基础路径,发布前修改这里
let path = "appIdentificationdemo";

module.exports = {
    // 项目路径地址
    publicPath: process.env.NODE_ENV === 'production' ? "/app/source/" : "/",
    // 静态资源文件地址
    assetsDir: path + "/static",
    // 静态资源文件
    indexPath: path + "/index.html",
    outputDir: path,
    lintOnSave: true,
    productionSourceMap: false,

    // 配置转发代理
    devServer: {
        port: 9999,
        disableHostCheck: true,
        proxy: {
            "^/jvs": {
                target: url,
                ws: true,
                pathRewrite: {
                    "^/jvs": "/jvs"
                }
            },
            "^/rule": {
                target: url,
                ws: true,
                pathRewrite: {
                    "^/rule": "/rule"
                }
            },
        }
    },
};

构建项目时输出目录路径需要以项目路径命名,如:appIdentificationdemo 静态资源由于是通过 nginx 固定地址代理所以需要将 build 路径也调整为对应的项目路径下

第四步:添加权限标识

  1. 登录轻应用管理后台
  2. 找到对应的轻应用
  3. 在权限管理中添加自定义权限标识
  4. 为需要访问该页面的用户或角色分配相应权限

权限标识与轻应用中的使用权限配置保持一致,用户可以手动添加权限标识。页面在初始化时会根据对应的版本渲染加载,判断是否显示隐藏权限。

权限说明如下:

1. 权限标识文件配置

1.1 文件创建

需要创建一个与项目名一致的JSON文件,例如项目名为appIdentificationdemo,则权限标识文件应命名为appIdentificationdemo.json,必须以.json为后缀。

1.2 文件位置

权限标识文件应放置在项目的public目录下,打包后会自动复制到输出目录中。以下示例是以 vue 项目为例

1.3 文件格式示例

复制代码
{
"/app/source/appIdentificationdemo/list": [
{
"name": "统计人数",
"permission": "jvs_count",
"url": [
{
"url": "/rule/openapi/appIdentificationname/demo/student/count",
"type": "GET"
}
]
},
{
"name": "删除学生",
"permission": "jvs_delete_user",
"url": [
{
"url": "/jvs-design/app/identification/use/dynamic/data/{modelIdentification}/{dataId}",
"type": "DELETE"
}
]
}
]
}

注意:路径需要与路由配置中的一致,例如在src/router/views/index.js中配置的路径。

2. 权限标识接口调用

2.1 接口地址

权限标识接口地址固定为:

复制代码
/jvs-design/base/app/design/permission/{应用标识}

其中{应用标识}需要在应用标识管理页面查看并替换。

2.2 调用方式

此接口必须最先请求且同步调用,确保在页面渲染前获取到权限信息。

在项目中,该接口在src/views/api/common.js中定义:

复制代码
async created () {
    // 同步获取权限接口 避免页面显示时会展示没有权限的内容
    const permissionListRes = await getAppPermission('appIdentificationname')
    if(permissionListRes.data.code==0){
    this.permissionsList = permissionListRes.data.data
    }
// 其他初始化代码
}

2.3 调用时机

在Vue组件的created或mounted生命周期中调用,确保权限信息在页面渲染前获取完成。

示例代码:

复制代码
async created () {
    // 同步获取权限接口 避免页面显示时会展示没有权限的内容
    const permissionListRes = await getAppPermission('appIdentificationname')
    if(permissionListRes.data.code==0){
    this.permissionsList = permissionListRes.data.data
    }
// 其他初始化代码
}

3. 接口返回格式

权限接口返回的数据格式如下:

复制代码
{
    "code": 0,
    "msg": "success",
    "data": [
    "jvs_count",
    "jvs_delete_user"
    ],
    "timestamp": 1761462391384
}

其中data字段为权限标识数组。

4. 权限使用方式

4.1 在模板中使用

使用v-if指令根据权限列表判断是否显示按钮或其它界面元素:

复制代码
<el-button type="primary" @click="addEditViewRow(null, 'add')">新增</el-button>
<div v-if="permissionsList.includes('jvs_count')">
  <span style="font-size: 12px;">调用逻辑示例</span>
  <el-tag style="margin-left: 10px;">当前用户总人数: {{userTotal}}</el-tag>
</div>

<!-- 在表格操作列中使用 -->
<el-button
type="text"
size="small"
style="color: #F56C6C;"
v-if="permissionsList.includes('jvs_delete_user')"   
@click="deleteRow(scope.row)">删除</el-button>

4.2 在方法中使用

可以在JavaScript方法中判断权限:

复制代码
methods: {
someMethod() {
if (this.permissionsList.includes('some_permission')) {
// 有权限时执行的操作
} else {
// 无权限时的处理
this.$message.warning('您没有执行此操作的权限');
}
}
}

5. 注意事项

  1. 权限标识文件名必须与项目名一致,且以.json为后缀
  2. 权限接口必须在页面初始化时最先同步调用
  3. 权限标识需要在应用标识管理页面预先配置
  4. 使用v-if而非v-show来控制权限元素的显示,避免无权限时元素仍然存在于DOM中
  5. 权限标识应具有良好的命名规范,建议使用有意义的英文命名

6. 权限标识命名规范

建议权限标识采用以下命名规范:

  • 使用英文小写字母和下划线组合
  • 命名应具有语义化,能够明确表示权限的作用
  • 可以采用功能_操作的形式,例如user_create、user_delete
  • 与业务相关的权限可以加上业务前缀,例如student_manage、teacher_query

这个文档详细说明了如何在项目中添加和使用权限标识,包括权限文件的配置、接口调用、返回格式以及使用方式。您可以根据项目实际情况对文档进行调整。

第五步:对接挂载页面

1. 项目打包

复制代码
npm run build

2. 部署文件

按照以下步骤完成部署:

  1. 在原有容器中将目录挂载到本地:

本地创建./data/app/source文件夹

2.3 挂载 jvs-ui项目

2.4 挂载 jvs-design-ui项目

复制代码
- ./data/app/source:/usr/share/nginx/html/app/source/
  1. 将打包后的项目文件夹(如appIdentificationdemo)复制到./data/app/source路径下

验证访问路径地址 http://gateway:10000/app/source/appIdentificationdemo/list 示下图:

3. 配置菜单挂载

  1. 登录系统管理后台
  2. 进入菜单管理模块
  3. 添加新菜单项,设置菜单名称和图标
  4. 配置菜单路径为: /app/source/appIdentificationdemo/list
  5. 为菜单项分配相应的权限标识

开发环境示例:

部署环境示例:

4. 验证访问

  1. 使用具有相应权限的用户账号登录系统
  2. 点击新添加的菜单项
  3. 确认页面正常加载并能正确显示数据

接口规范参考

基础路径

/jvs-design/app/identification/use/dynamic/data

功能与接口对照表

其它接口说明 包含数据模型的新增修改删除导出等,对模型操作的接口和自定义逻辑编排接口的操作。

功能与接口对照表

|---------------|----------------------------------------------------------------------------------------------------------|
| 功能 | 接口地址 |
| (通用)批量删除数据 | DELETE /jvs-design/app/identification/use/dynamic/data/{modelIdentification}/batch/delete |
| (通用)删除单条数据 | DELETE /jvs-design/app/identification/use/dynamic/data/{modelIdentification}/{dataId} |
| (通用)查询字段值 | GET /jvs-design/app/identification/use/dynamic/data/{modelIdentification}/{dataId} |
| (通用)查询全部数据 | GET /jvs-design/app/identification/use/dynamic/data/list/{modelIdentification}支持 POST 请求方式 |
| (通用)分页查询 | POST /jvs-design/app/identification/use/dynamic/data/query/page/${modelIdentification} |
| (通用)查询单条原始数据 | GET /jvs-design/app/identification/use/dynamic/data/single/{modelIdentification}/{dataId} |
| (通用)查询单条转换后数据 | GET /jvs-design/app/identification/use/dynamic/data/single/transformation/{modelIdentification}/{dataId} |
| (通用)新增/修改数据 | POST /jvs-design/app/identification/use/dynamic/data/save/{modelIdentification} |
| 自定义 调用业务逻辑 | POST /rule/openapi/{appIdentification}/{ruleIdentify}需配置事件触发方式逻辑 |

标识说明

{appIdentification} 应用标识(需在应用中心维护源码标识){modelIdentification} 模型标识(需在应用中心维护源码标识){ruleIdentify} 逻辑标识(支持 / 开头的动态路径)

注意事项

  1. 确保网络连接正常,能够访问网关地址
  2. 正确配置Token,确保接口调用权限
  3. 部署时保持路径一致性
  4. 合理设置权限标识,确保安全性
  5. 在生产环境中移除调试用的临时Token
  6. 业务逻辑创建时选择事件触发

通过以上五个步骤,您就可以成功创建一个自定义前端页面并将其接入到现有系统中。

在线demo:https://app.bctools.cn

基础框架开源地址:https://gitee.com/software-minister/jvs

相关推荐
谢尔登2 小时前
【React】React组件的渲染过程分为哪几个阶段?
前端·javascript·react.js
MediaTea2 小时前
Python 第三方库:Flask(轻量级 Web 框架)
开发语言·前端·后端·python·flask
5***o5002 小时前
前端构建工具缓存清理,解决依赖问题
前端·缓存
lcc1873 小时前
Vue Vue与VueComponent的关系
前端·vue.js
无敌最俊朗@3 小时前
Vue 3 概况
前端·javascript·vue.js
摆烂工程师3 小时前
今天 Cloudflare 全球事故,连 GPT 和你的网站都一起“掉线”了
前端·后端·程序员
拉不动的猪3 小时前
一文搞懂:localhost和局域网 IP 的核心区别与使用场景
前端·javascript·面试
亿元程序员3 小时前
你支持游戏内显示电量、信号或时间吗?
前端
阿珊和她的猫4 小时前
HTTP:Web 世界的基石协议详解
前端·网络协议·http