# 简要介绍

此项目的源码来自开源项目 https://gitee.com/panjiachen/vue-admin-template

详细的使用教程,请参考开源项目。(注:如果是新手,建议前往学习)

下面,我们重点介绍如何快速开发一个功能

# 创建前端工程

通过菜单打开【我的系统】->【prj_c】->【前端工程】功能,点击【创建前端工程】打开对话框,创建前端工程 prj_vue2,如图:

prj_vue2源代码目录结构,如图:

# 重点掌握的源代码

├─ src                       // 源代码
│  ├─ api                    // 所有请求
│  │  └─ call_api.js         // call_svc.js 中定义的函数调用此文件的api,实现调用服务
│  ├─ store                  // 全局 store
│  │  └─ modules
│  │     ├─ call_svc.js      // vue 模板通过此文件定义的全局接口调用服务(重点掌握)
│  │     └─ user.js          // 用户登录接口
│  ├─ utils                  // 公用方法
│  │  └─ sign.js             // 服务的签名函数
│  └─ views                  // vue 模板的目录
│  │  └─ ...                 // 具体功能界面的源码文件
├─ .env.development          // 开发环境变量
├─ .env.production           // 生产环境变量
1
2
3
4
5
6
7
8
9
10
11
12
13

# call_api.js 文件

这里定义了 call_api、multipart_upload、download 几个接口,也可以根据需求进行扩展;

所有服务的请求都通过 call_api() 方法来访问服务api

import request from '@/utils/request'

/**
 * post 请求,具体访问的服务在 Request_Obj 对象中指定
 * @param {*} req 的数据结构为 Request_Obj 类型
 * @returns 返回的结果
 */
export function call_api(req = {}, _headers = { 'Content-Type': 'application/json; charset=utf-8' }, _baseURL = '') {
  return request({
    baseURL: (_baseURL === '' ? process.env.VUE_APP_BASE_API : _baseURL),
    url: '/api',
    method: 'post',
    data: req,
    headers: _headers
  })
}

export function multipart_upload(req = {}, _headers = { 'Content-Type': 'multipart/form-data' }, _baseURL = '') {
  let reqstr = encodeURIComponent(req.reqstr)
  return request({
    baseURL: (_baseURL === '' ? process.env.VUE_APP_BASE_API : _baseURL),
    url: '/multipart_upload?reqstr=' + reqstr,
    method: 'post',
    data: req.body,
    headers: _headers
  })
}

export function download(reqstr = '', _headers = { 'Content-Type': 'text/plain' }, _baseURL = '') {
  reqstr = encodeURIComponent(reqstr)
  return request({
    baseURL: (_baseURL === '' ? process.env.VUE_APP_BASE_API : _baseURL),
    url: '/download?reqstr=' + reqstr,
    method: 'get',
    headers: _headers,
    responseType: 'blob' // 告诉 axios 返回的是 Blob 对象(文件),必须要设置该参数。否则,返回的数据将不正确
  })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# call_svc.js 文件

这里定义了3个方法:call_kedao_api(调用服务)、call_upload_api(上传文件)、call_download_api(下载文件)

如果要对服务的数据进行加解密,在此增加相应的代码

import { call_api, multipart_upload, download } from '@/api/call_api'
import { deepClone } from '@/utils';
import { sign } from "@/utils/sign";
import { getToken, getUsr_id, getMain_usr_id, getOrg_id, getSys_id} from '@/utils/auth';

const state = {}
const mutations = {}
const actions = {
  call_kedao_api({ commit }, req_obj) {
    let request_obj = {
      appid: process.env.VUE_APP_APP_ID,
      sys_name: process.env.VUE_APP_SYS_NAME,
      mdl_name: req_obj.mdl_name,
      svc_name: req_obj.svc_name,
      body: {
        sys_head: { 
          usr_id: getUsr_id(), 
          org_id: getOrg_id(), 
          mdl_func_id: "", 
          login_key: getToken()
        },
        data: deepClone(req_obj.data)
      }
    }

    // 处理 headers
    let headers = {}
    headers['Content-Type'] = 'application/json; charset=utf-8'

    // 加密处理(根据自己业务的需要进行加密处理)
    /*
    if (process.env.VUE_APP_IS_ENCRYPT === '1') {
      if (typeof (request_obj.data) === 'object') {
        // 将对象转换为字符串
        request_obj.data = JSON.stringify(request_obj.data)
      }
      request_obj.data = AES_CBC_encrypt(request_obj.data)
    }
    */

    // 签名处理
    request_obj.sign = sign(request_obj)
    // 处理异步任务
    return new Promise((resolve, reject) => {
      call_api(request_obj, headers).then(response_obj => {
        if (typeof response_obj !== 'object') {
          // 如果服务中做了加密处理,这里进行相应的解密
          /*
            if (process.env.VUE_APP_IS_ENCRYPT === '1') {
              response_obj = JSON.parse(AES_CBC_decrypt(response_obj);
            }
          */
          resolve(JSON.parse(response_obj));
        } else {
          resolve(response_obj)
        }
      }).catch(error => {
        let out_obj = {
          code: -1,
          err_msg: error
        }
        resolve(out_obj)
      })
    })
  },
  
  /**
   * 上传文件
   * @param {*} param0 
   * @param {*} formData 要上传的文件是一个数组: [{name:'', path:''},{},...]; 其中,name 为上传文件的服务器端目标路径,path为本地要上传的文件路径
   * @returns 
   */
  call_upload_api({ commit }, formData) {
    // 生成参数对象
    // 说明:在上传文件时,会调用 sys_commons 模块下的 svc_verify_login_identity 服务,校验用户身份的有效性,如果身份不合法,则不允许上传
    let verify_request_obj = {
      appid: process.env.VUE_APP_APP_ID,
      sys_name: process.env.VUE_APP_SYS_NAME,
      mdl_name: 'sys_commons',
      svc_name: 'svc_verify_login_identity',
      body: {
        sys_head: {
          usr_id: getUsr_id(), 
          org_id: getOrg_id(), 
          sys_id: getSys_id(), 
          mdl_func_id: "", 
          login_key: getToken()
        },
        data: ''    // 自定义校验数据
      }
    }

    // 组织参数并进行签名
    verify_request_obj = sign(verify_request_obj)
    let req_str = JSON.stringify(verify_request_obj);

    let request_obj = {
      body: formData,
      reqstr: req_str
    }

    // 处理 headers
    let headers = {}
    headers['Content-Type'] = 'multipart/form-data'

    // 处理异步任务
    return new Promise((resolve, reject) => {
      multipart_upload(request_obj, headers).then(response_obj => {
        if (typeof response_obj !== 'object') {
          // 如果服务中做了加密处理,这里进行相应的解密
          /*
            if (process.env.VUE_APP_IS_ENCRYPT === '1') {
              response_obj = JSON.parse(AES_CBC_decrypt(response_obj);
            }
          */
          resolve(JSON.parse(response_obj));
        } else {
          resolve(response_obj)
        }
      }).catch(error => {
        let out_obj = {
          code: -1,
          err_msg: error
        }
        resolve(out_obj)
      })
    })
  },

  /**
   * 
   * @param {*} param0 
   * @param {*} filename 为服务器上的文件路径(绝对路径或相对路径)
   * @returns 
   */
  call_download_api({ commit }, filename) {
    // 生成参数对象
    // 说明:在下载文件时,会调用 sys_commons 模块下的 svc_verify_login_identity 服务,校验用户身份的有效性,如果身份不合法,则不允许下载
    let request_obj = {
      appid: process.env.VUE_APP_APP_ID,
      sys_name: process.env.VUE_APP_SYS_NAME,
      mdl_name: 'sys_commons',
      svc_name: 'svc_verify_login_identity',
      body: {
        sys_head: {
          usr_id: getUsr_id(), 
          org_id: getOrg_id(), 
          sys_id: getSys_id(), 
          mdl_func_id: "", 
          login_key: getToken()
        },
        data: filename      // 要下载的文件
      }
    }

    // 加密处理(根据自己业务的需要进行加密处理)
    /*
    if (process.env.VUE_APP_IS_ENCRYPT === '1') {
      if (typeof (request_obj.data) === 'object') {
        // 将对象转换为字符串
        request_obj.data = JSON.stringify(request_obj.data)
      }
      request_obj.data = AES_CBC_encrypt(request_obj.data)
    }
    */

    // 签名
    request_obj.sign = sign(request_obj)
    // 对象转字符串
    let reqstr = JSON.stringify(request_obj)

    // 处理 headers
    let headers = {}
    headers['Content-Type'] = 'text/plain'

    // 处理异步任务
    return new Promise((resolve, reject) => {
      download(reqstr, headers).then(response_obj => {
        if (typeof response_obj !== 'object') {
          // 如果服务中做了加密处理,这里进行相应的解密
          /*
            if (process.env.VUE_APP_IS_ENCRYPT === '1') {
              response_obj = JSON.parse(AES_CBC_decrypt(response_obj);
            }
          */
          resolve(JSON.parse(response_obj));
        } else {
          resolve(response_obj)
        }
      }).catch(error => {
        reject('')
      })
    })
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202

# user.js 文件

这里单独封装了登录和刷新页面获取路由的方法,同样的,如果要对服务的数据进行加解密,在相应的方法中增加代码

这里重点掌握 login() 方法,登录页面在 src/views/login/index.vue

import { call_api } from '@/api/call_api'
import { sign } from "@/utils/sign";
import { getToken, setToken, setUsr_id,setOrg_id, removeToken, getUsr_id, getOrg_id, setUsr_name } from '@/utils/auth'
import { resetRouter } from '@/router'
import { addDynamicRoutes } from '@/utils/add_dynamic_routes'

const getDefaultState = () => {
  return {
    token: getToken(),
    name: '',
    avatar: '',
    roles: [],
    userRoutes: []
  }
}

const state = getDefaultState()

const mutations = {
  RESET_STATE: (state) => {
    Object.assign(state, getDefaultState())
  },
  SET_TOKEN: (state, token) => {
    state.token = token
  },
  SET_NAME: (state, name) => {
    state.name = name
  },
  SET_AVATAR: (state, avatar) => {
    state.avatar = avatar
  },
  SET_ROLES: (state, roles) => {
    state.roles = roles
  },
  SET_ROUTES: (state, routes) => {
    state.userRoutes = routes
  }
}

const actions = {
  // user login
  login({ commit }, req_obj) {
    let request_obj = {
      appid: process.env.VUE_APP_APP_ID,
      sys_name: process.env.VUE_APP_SYS_NAME,
      mdl_name: 'sys_login',
      svc_name: 'svc_login',
      body: {
        sys_head: { 
          usr_id: "",      // 当前登录用户的id,在登录时返回并写入cookie中,通过 cookie 获取
          org_id: "",      // 当前登录用户所属的机构id,在登录时返回并写入cookie中,通过 cookie 获取
          sys_id: "",      // 业务系统id,在登录时返回并写入cookie中,通过 cookie 获取
          mdl_func_id: "", // 功能id,当前功能的id,通过共名称查找。作用是根据用户是否具有操作该功能的权限来控制此次服务的执行
          login_key: ''    // 登录用户的 token
        },
        data: req_obj
      }
    }

    // 加密处理(根据自己业务的需要进行加密处理)
    /*
    if (process.env.VUE_APP_IS_ENCRYPT === '1') {
      if (typeof (request_obj.data) === 'object') {
        // 将对象转换为字符串
        request_obj.data = JSON.stringify(request_obj.data)
      }
      request_obj.data = AES_CBC_encrypt(request_obj.data)
    }
    */
    // 签名
    request_obj.sign = sign(request_obj)
    let headers = {}
    headers['Content-Type'] = 'application/json; charset=utf-8'
    // 处理异步任务
    return new Promise((resolve, reject) => {
      call_api(request_obj, headers).then(response_obj => {
        // 如果服务中做了加密处理,这里进行相应的解密
        /*
          if (process.env.VUE_APP_IS_ENCRYPT === '1') {
            response_obj = JSON.parse(AES_CBC_decrypt(response_obj);
          }
        */

        if (response_obj.code !== 0) {
          resolve(response_obj)
        }

        // 生成动态路由
        const userRoutes = addDynamicRoutes(response_obj.data.obj_2)
        commit('SET_ROUTES', userRoutes) // 路由

        commit('SET_TOKEN', response_obj.data.obj_1.login_key)
        commit('SET_ROLES', ['admin']) // 角色,这里固定值,因为服务没有返回角色
        commit('SET_NAME', response_obj.data.obj_1.usr_name) // 用户名称
        // 设置 cookies
        setToken(response_obj.data.obj_1.login_key)
        setUsr_id(response_obj.data.obj_1.usr_id)
        setOrg_id(response_obj.data.obj_1.org_id)
        setUsr_name(response_obj.data.obj_1.usr_name)
        
        resolve(response_obj)
      }).catch(error => {
        let out_obj = {
          code: -1,
          err_msg: error
        }
        resolve(out_obj)
      })
    })
  },

  // get user info
  getInfo({ commit, state }) {
    let request_obj = {
      appid: process.env.VUE_APP_APP_ID,
      sys_name: process.env.VUE_APP_SYS_NAME,
      mdl_name: 'sys_login',
      svc_name: 'svc_get_userInfo',
      body: {
        sys_head: { 
          usr_id: getUsr_id(), 
          org_id: getOrg_id(), 
          mdl_func_id: "", 
          login_key: getToken() 
        },
        data: {}
      }
    }

    // 加密处理(根据自己业务的需要进行加密处理)
    /*
    if (process.env.VUE_APP_IS_ENCRYPT === '1') {
      if (typeof (request_obj.data) === 'object') {
        // 将对象转换为字符串
        request_obj.data = JSON.stringify(request_obj.data)
      }
      request_obj.data = AES_CBC_encrypt(request_obj.data)
    }
    */

    // 签名
    request_obj.sign = sign(request_obj)
    
    let headers = {}
    headers['Content-Type'] = 'application/json; charset=utf-8'

    // 处理异步任务
    return new Promise((resolve, reject) => {
      call_api(request_obj, headers).then(response_obj => {
        // 如果服务中做了加密处理,这里进行相应的解密
        /*
          if (process.env.VUE_APP_IS_ENCRYPT === '1') {
            response_obj = JSON.parse(AES_CBC_decrypt(response_obj);
          }
        */
      
        const userRoutes = addDynamicRoutes(response_obj.data.obj_2)
        commit('SET_ROUTES', userRoutes) // 路由
        commit('SET_TOKEN', getToken())
        commit('SET_ROLES', ['admin'])   // 角色,这里固定值,因为服务没有返回角色
        commit('SET_NAME', response_obj.data.obj_1.usr_name) // 用户名称
        
        resolve(response_obj)
      }).catch(error => {
        let out_obj = {
          code: -1,
          err_msg: error
        }
        resolve(out_obj)
      })
    })
  },

  // user logout
  logout({ commit }) {
    return new Promise((resolve, reject) => {
      removeToken() // must remove  token  first
      resetRouter()
      commit('RESET_STATE')
      resolve()
      this.$destroy (true)
    })
  },

  // remove token
  resetToken({ commit }) {
    return new Promise(resolve => {
      removeToken() // must remove  token  first
      commit('RESET_STATE')
      resolve()
    })
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200

# sign.js 文件

签名算法

import { SHA256 } from '@/utils/crypto'

export function sign(request_obj) {
  // 拼接 SHA256 签名的字符串
  let str_sign = ''
  str_sign += 'appid=' + request_obj.appid
  str_sign += '&body=' + (typeof (request_obj.body) === 'object' ? JSON.stringify(request_obj.body) : request_obj.body)
  str_sign += '&mdl_name=' + request_obj.mdl_name
  str_sign += '&svc_name=' + request_obj.svc_name
  str_sign += '&sys_name=' + request_obj.sys_name
  str_sign += '&key=' + process.env.VUE_APP_SIGN_KEY

  // 进行 md5/SHA256 加密,并给签名赋值
  // return MD5(str_sign).toString()
  return SHA256(str_sign).toString()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# .env.* 环境变量文件

VUE_APP_BASE_API 为访问服务的服务器 URL,需要手动设置,其他的变量会默认设置,或根据实际情况,手动设置,如:

# just a flag
ENV = 'development'

# 使用 VUE_APP_ 开头的变量会被 webpack 自动加载

# base api
VUE_APP_BASE_API = 'http://192.168.43.131'

# API参数中的appid
VUE_APP_APP_ID = '9d6ab21aab7c491a80256fbc9180c4f8'

# API参数中参与签名的key
VUE_APP_SIGN_KEY = '50dfe69f33904468a32214d9ede29395230cbdc196e541a6b380ee7b50eca3939eb6c66f90ec44b395dc39533a2a0ab77ab4ea77aa2e45809a77647e270fe862'

# API参数的系统名称
VUE_APP_SYS_NAME = 'prj_c'

# 是否AES加密
VUE_APP_IS_ENCRYPT = '0'

# AES加密密钥和向量  不要使用这3个符号  ~ |  &
VUE_APP_AES_KEY = ''
VUE_APP_AES_IV = ''

# 部署时相对于www根目录的路径
VUE_APP_PUBLIC_PATH = '/'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

# 在 *.vue 模板文件中调用服务

<template>
  <div>
    <el-button type="primary" @click="onQuery" size="mini">查询</el-button>
  </div>
</template>

<script>
export default {
    data() {
        return {
        }
    },
    methods: {
        // 查询
        onQuery() {
            // 组织服务API的请求参数
            let req_obj = {
                mdl_name:'basic_func_funcRounter',    // 服务所在的模块名称
                svc_name:'f_get_functionsInfor',      // 服务名称
                data: {
                    // 服务的入参数据
                }
            }
            // 调用服务
            this.$store.dispatch('call_svc/call_kedao_api',req_obj).then(res => {
                if (res.code === 0) {
                    // 处理服务返回的数据
                    // res.data
                } else {
                    this.$message({
                    message: res.err_msg,
                    type: 'error',
                    showClose: true,
                    duration: 6000,
                    offset: window.screen.height / 2.62
                    });
                }
            }).finally(() => {
                // 
            })
        }
    }
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

如果想了解完整的服务API的请求参数,参考 src/store/modules/call_svc.js 的 call_kedao_api 方法,如:

  call_kedao_api({ commit }, req_obj) {
    let request_obj = {
      appid: process.env.VUE_APP_APP_ID,
      sys_name: process.env.VUE_APP_SYS_NAME,
      mdl_name: req_obj.mdl_name,
      svc_name: req_obj.svc_name,
      body: {
        sys_head: { 
          usr_id: getUsr_id(), 
          org_id: getOrg_id(), 
          mdl_func_id: "", 
          login_key: getToken()
        },
        data: deepClone(req_obj.data)
      }
    }

    // 处理 headers
    let headers = {}
    headers['Content-Type'] = 'application/json; charset=utf-8'

    // 加密处理(根据自己业务的需要进行加密处理)
    /*
    if (process.env.VUE_APP_IS_ENCRYPT === '1') {
      if (typeof (request_obj.data) === 'object') {
        // 将对象转换为字符串
        request_obj.data = JSON.stringify(request_obj.data)
      }
      request_obj.data = AES_CBC_encrypt(request_obj.data)
    }
    */

    // 签名处理
    request_obj.sign = sign(request_obj)

    ...
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# 增加一个vue文件

在 kedao-creator 中的【前端工程】页面中,展开工程文件,打开到 views 文件夹,右键,增加一个文件夹:testModule,之后右键 testModule 增加一个 vue 文件 test_function.vue,如:

在左侧的功能树中,单击新增加的 "test_function.vue" 文件,可以看到一个默认的界面,如:

目前界面设计器的功能还在开发中,暂时不开放可视化界面设计功能

我们通过 VSCode 直接在 test_function.vue 模板文件上编写代码,默认生成的模板代码,如:

<template>
  <div class='app-container' style="height: 100%;">
    <el-container>
      <el-header height="100%" style="align-content: center;">
        <!-- 查询条件 -->
        <el-form ref="form_query_function" :model="svc_request_data" label-width="80px">
          <el-row>
            <el-col :span="6">
              <el-form-item label="查询条件1">
                <el-input v-model="svc_request_data.field_name1"></el-input>
              </el-form-item>
            </el-col>
            <el-col :span="6">
              <el-form-item label="查询条件2">
                <el-input v-model="svc_request_data.field_name2"></el-input>
              </el-form-item>
            </el-col>
            <el-col :span="6">
              <el-form-item label="查询条件3">
                <el-input v-model="svc_request_data.field_name3"></el-input>
              </el-form-item>
            </el-col>
            <el-col :span="6">
              <el-form-item label="查询条件4">
                <el-input v-model="svc_request_data.field_name4"></el-input>
              </el-form-item>
            </el-col>
          </el-row>
          <el-row>
            <el-col span="24">
              <div style="float: right;">
                <el-button type="primary" @click="onQuery">查询</el-button>
                <el-button type="primary" @click="onAdd">增加</el-button>
                <el-button type="primary" @click="onReset">重置</el-button>
              </div>
            </el-col>
          </el-row>
        </el-form>
      </el-header>
      <el-main>
        <!-- 数据表格 -->
        <el-table :height="tableHeight"
          border
          stripe 
          style="margin-top: 6px;"
          :cell-style="{padding: '3px'}"
          :data="lst_svc_response_data" 
          :header-cell-style="{background:'rgb(245,247,250)',color:'#606266','text-align':'center'}"
          v-loading.body="tableLoading" 
          highlight-current-row 
          tooltip-effect="light">
          <el-table-column show-overflow-tooltip label="字段名1" align="left" width="180px">
            <template slot-scope="scope">
              <span>{{scope.row.field_name1}}</span>
            </template>
          </el-table-column>
          <el-table-column show-overflow-tooltip label="字段名2" align="left" width="180px">
            <template slot-scope="scope">
              <span>{{scope.row.field_name2}}</span>
            </template>
          </el-table-column>
          <el-table-column show-overflow-tooltip label="字段名3" align="left" width="180px">
            <template slot-scope="scope">
              <span>{{scope.row.field_name3}}</span>
            </template>
          </el-table-column>
          <el-table-column show-overflow-tooltip label="字段名4" align="left">
            <template slot-scope="scope">
              <span>{{scope.row.field_name4}}</span>
            </template>
          </el-table-column>
          <el-table-column show-overflow-tooltip label="操作" fixed="right"  align="center" width="160px" >
            <template slot-scope="scope">
              <el-button type="text" @click="onRowEdit(scope.row)">编辑</el-button>
              <el-button type="text" @click="onRowDelete(scope.row)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
      </el-main>
    </el-container>

    <!-- 增加对话框(略) -->
    <!-- 编辑对话框(略)-->
  </div>
</template>

<script>
export default {
  data(){
    return{
      tableHeight: 0,
      tableLoading: false,
      showAddDialogFlag: false,
      showEditDialogFlag: false,
      svc_request_data: {},        // 服务请求参数对象
      lst_svc_response_data: []    // 服务响应参数对象
    }
  },
  created() {
    // 180是表格外其它布局占的高度,这个数值根据自己实际情况修改
    this.tableHeight = window.innerHeight - 264
  },
  activated () {
    /**
     * 解决页面切换时行错乱
     */
    this.$nextTick(() => {
      this.$refs.tbServerList.doLayout()
    })
  },
  mounted() {
    // 监听浏览器窗口变化,动态计算表格高度
    window.onresize = () => {
      return (() => {
        this.tableHeight = window.innerHeight - 264
      })()
    }
  },
  methods:{
    onQuery() {
      // 组织或校验服务的请求参数

      // 调用 XXX 服务(异步)
      this.xxx_svc_name(this.svc_request_data)
    },
    onAdd() {
      // 设置显示增加对话框
      this.showAddDialogFlag = true
    },
    onReset() {
      // 重置查询条件
      this.svc_request_data = {
        field_name1: "",
        field_name2: "",
        field_name3: "",
        field_name4: ""
      }
    },
    onRowEdit(row) {
      // 设置显示编辑对话框
      this.showEditDialogFlag = true
    },
    onRowDelete(row) {
      this.$confirm(`确定要删除该记录吗`, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'confirm',
      }).then(()=> {
        // 确定之后做的事情
      }).catch(err => {
        // 异常错误
        // console.error(err)
      })
    },
    xxx_svc_name(in_data) {
      let that = this
      let req_obj = {
        mdl_name:'模块名称',
        svc_name:'服务名称',
        data: in_data
      }
      this.tableLoading = true
      // 调用全局服务api(异步)
      this.$store.dispatch('call_svc/call_kedao_api',req_obj).then(res => {
        if (res.code === 0) {
          // 接收服务返回的结果
          that.lst_svc_response_data = res.data
          // 处理服务返回的逻辑
          // ...
        } else {
          this.$message({
            message: res.err_msg,
            type: 'error',
            showClose: true,
            duration: 6000,
            offset: window.screen.height / 2.62
          })
        }
      }).finally(() => {
        that.tableLoading = false
      })
    }
  }
}
</script>

<style scoped>
</style>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188

# 启动 prj_vue2

如果已经启动,则跳过此步

进入到 src_front/kmyckj/prj_c/prj_vue2 目录,执行命令:

npm run dev
1

启动成功,如:

You may use special comments to disable some warnings.
Use // eslint-disable-next-line to ignore the next line.
Use /* eslint-disable */ to ignore all warnings in a file.

  App running at:
  - Local:   http://localhost:8082/ 
  - Network: http://192.168.43.131:8082/
1
2
3
4
5
6
7

# 配置路由

登录 prj_vue2,打开【基础功能】-【功能管理】并单击【查询】按钮进行查询,在第一行的【基础功能】中,单击【增加同级】按钮,增加 testModule 模块,如:

之后,在新增加的 测试模块 这行,单击【增加下级】按钮,增加 test_function 功能,如:

增加成功后,新增加的模块和功能会自动出现在菜单上,如:

单击菜单【测试功能】,则会打开新增加的功能,如:

# 在 vue 中调用服务

在这里,我们实现一个服务的查询,并展示服务返回的结果,以服务 svc_test_query_function 为例

# 服务 svc_test_query_function 的相关信息

服务所在模块:mdl_test

服务名称:svc_test_query_function

服务的入参:SYS_FUNCTION

服务的出参(C++):vector< SYS_FUNCTION >

服务的出参(Java):List< SYS_FUNCTION >

SYS_FUNCTION 的数据结构(C++):

class SYS_FUNCTION
{
public:
    string func_id = "";			      // 功能ID
    string func_parent_id = "";			// 父功能ID
    string func_code = "";			    // 功能名称/路由name
    string menu_title = "";		    	// 菜单名称
    string router_path = "";			  // 路由路径
    string component_path = "";			// 组件路径
    string icon = "";		           	// 图标
    int func_type = 0;		        	// 类型(有组件路径 1(详细功能,没有下级) ,否则0(节点下有详细功能))
    int sort_num = 0;			          // 统计排列序号
};
1
2
3
4
5
6
7
8
9
10
11
12
13

SYS_FUNCTION 的数据结构(Java):

public class SYS_FUNCTION  {
    public String func_id = "";			        // 功能ID
    public String func_parent_id = "";			// 父功能ID
    public String func_code = "";			      // 功能名称/路由name
    public String menu_title = "";		    	// 菜单名称
    public String router_path = "";			    // 路由路径
    public String component_path = "";			// 组件路径
    public String icon = "";			// 图标
    public int func_type = 0;			// 类型(有组件路径 1(详细功能,没有下级) ,否则0(节点下有详细功能))
    public int sort_num = 0;			// 统计排列序号
}
1
2
3
4
5
6
7
8
9
10
11

# 修改服务名称

将 xxx_svc_name 修改为 svc_test_query_function;并修改服务方法中的 模块名称 和 服务名称,如:

export default {
  ...
  methods:{
    onQuery() {
      // 组织或校验服务的请求参数

      // 调用 svc_test_query_function 服务(异步)
      this.svc_test_query_function(this.svc_request_data)   // 修改 xxx_svc_name
    },

    svc_test_query_function(in_data) {
      let that = this
      let req_obj = {
        mdl_name:'mdl_test',                       // 修改 模块名称
        svc_name:'svc_test_query_function',        // 修改 服务名称
        data: in_data
      }

      ...
    }

    ...
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 修改服务的请求参数对象

修改 svc_request_data 中的 field_name1, field_name2, ... 为具体的字段,如:

field_name1 改为 func_code // 功能名称

field_name2 改为 menu_title // 菜单名称

field_name3 改为 router_path // 路由路径

field_name4 改为 component_path // 组件路径

修的代码如下:

<template>
  <div class='app-container' style="height: 100%;">
    <el-container>
      <el-header height="100%" style="align-content: center;">
        <!-- 查询条件 -->
        <el-form ref="form_query_function" :model="svc_request_data" label-width="80px">
          <el-row>
            <el-col :span="6">
              <el-form-item label="功能名称">
                <el-input v-model="svc_request_data.func_code"></el-input>
              </el-form-item>
            </el-col>
            <el-col :span="6">
              <el-form-item label="菜单名称">
                <el-input v-model="svc_request_data.menu_title"></el-input>
              </el-form-item>
            </el-col>
            <el-col :span="6">
              <el-form-item label="路由路径">
                <el-input v-model="svc_request_data.router_path"></el-input>
              </el-form-item>
            </el-col>
            <el-col :span="6">
              <el-form-item label="组件路径">
                <el-input v-model="svc_request_data.component_path"></el-input>
              </el-form-item>
            </el-col>
          </el-row>
          <el-row>
            <el-col span="24">
              <div style="float: right;">
                <el-button type="primary" @click="onQuery">查询</el-button>
                <el-button type="primary" @click="onAdd">增加</el-button>
                <el-button type="primary" @click="onReset">重置</el-button>
              </div>
            </el-col>
          </el-row>
        </el-form>
      </el-header>
      ...
    </el-container>
  ...
  </div>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
    onReset() {
      // 重置查询条件
      this.svc_request_data = {
        func_code: "",
        menu_title: "",
        router_path: "",
        component_path: ""
      }
    },
1
2
3
4
5
6
7
8
9

修改完成,记得保存。

# 修改服务的响应参数对象

修改 lst_svc_response_data 中的 field_name1, field_name2, ... 为具体的字段,如:

field_name1 改为 func_code // 功能名称

field_name2 改为 menu_title // 菜单名称

field_name3 改为 router_path // 路由路径

field_name4 改为 component_path // 组件路径

修的代码如下:

<template>
  <div class='app-container' style="height: 100%;">
    <el-container>
      ...
      <el-main>
        <!-- 数据表格 -->
        <el-table :height="tableHeight"
          border
          stripe 
          style="margin-top: 6px;"
          :cell-style="{padding: '3px'}"
          :data="lst_svc_response_data" 
          :header-cell-style="{background:'rgb(245,247,250)',color:'#606266','text-align':'center'}"
          v-loading.body="tableLoading" 
          highlight-current-row 
          tooltip-effect="light">
          <el-table-column show-overflow-tooltip label="功能名称" align="left" width="180px">
            <template slot-scope="scope">
              <span>{{scope.row.func_code}}</span>
            </template>
          </el-table-column>
          <el-table-column show-overflow-tooltip label="菜单名称" align="left" width="180px">
            <template slot-scope="scope">
              <span>{{scope.row.menu_title}}</span>
            </template>
          </el-table-column>
          <el-table-column show-overflow-tooltip label="路由路径" align="left" width="180px">
            <template slot-scope="scope">
              <span>{{scope.row.router_path}}</span>
            </template>
          </el-table-column>
          <el-table-column show-overflow-tooltip label="组件路径" align="left">
            <template slot-scope="scope">
              <span>{{scope.row.component_path}}</span>
            </template>
          </el-table-column>
          <el-table-column show-overflow-tooltip label="操作" fixed="right"  align="center" width="160px" >
            <template slot-scope="scope">
              <el-button type="text" @click="onRowEdit(scope.row)">编辑</el-button>
              <el-button type="text" @click="onRowDelete(scope.row)">删除</el-button>
            </template>
          </el-table-column>
        </el-table>
      </el-main>
    </el-container>
  ...
  </div>
</template>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

修改完成,记得保存。

# 查看修改后的效果

回到【测试功能】界面,点击查询,将得到调用服务返回的结果,如:

如果页面没有改变,或者调不到服务,按 F5 刷新后再试。

至此,一个简单的 vue 页面开发完成。